Reputation: 635
I am trying to add an hline shape in a plotly graph using a secondary y-axis. The plot correctly shows the data for the two distinct y-axes, but the hline is being plotted on primary axis despite using yref='y2' in the add_hline function.
I realize that I can work around this using add_shape instead of hline, but I was trying to determine if I was doing something wrong.
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
# simple example with hline
df = px.data.iris()
fig = px.scatter(df, x="petal_length", y="petal_width")
fig.add_traces(go.Scatter(y=np.arange(1, 7), mode="lines+markers", yaxis='y2'))
fig.add_hline(y=2, line_dash='dash', line_color='Red', yref='y2')
fig.update_layout(
width=400,
height=400,
plot_bgcolor="white",
xaxis=dict(linecolor="black"),
yaxis=dict(linecolor="black"),
yaxis2=dict(
title="yaxis2 title",
overlaying="y",
side="right",
linecolor="black",
)
)
fig.update_xaxes(ticks="outside")
fig.update_yaxes(ticks="outside")
fig.show()
Upvotes: 7
Views: 2823
Reputation: 1
I believe this is a bug as well however, if anyone comes across this in the future, it can be done. To add some context to this problem, when you call the px.scatter()
method, you generate a figure object that contains subplots. Specifically, one with a size of (1,1), that is 1 row and 1 column. In order to plot a "shape" such as an hline on a secondary axis in a figure object that contains subplots, you must specify that the specific subplot 'sepcs' has a secondary y-axis. The only way to do this that I am aware of is to create the figure object using the subplots.make_subplots()
method and provide a 'specs' dictionary. Here is your example with the proper hline but using the subplots.make_subplots()
method:
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
from plotly import subplots
# simple example with hline
df = px.data.iris()
fig = subplots.make_subplots(rows=1, cols=1,specs=[[{'secondary_y':True}]])
fig.add_trace(go.Scatter(x=df['petal_length'], y=df['petal_width'],mode='markers'), row=1, col=1)
fig.add_trace(go.Scatter(y=np.arange(1,7),mode='lines+markers',yaxis='y2'), row=1, col=1,secondary_y=True)
fig.add_hline(y=2,row=1,col=1,line_dash="dash",line_color="Red",yref='y2',secondary_y=True)
fig.update_layout(
width=400,
height=400,
plot_bgcolor="white",
xaxis=dict(linecolor="black"),
yaxis=dict(linecolor="black"),
yaxis2=dict(
title="yaxis2 title",
overlaying="y",
side="right",
linecolor="black",
)
)
fig.update_xaxes(ticks="outside")
fig.update_yaxes(ticks="outside")
fig.show()
.
I will also note that you don't need to specify row=1
col=1
all over the place like in the add_hline()
method and the add_trace()
method since by default the row and col arguments are 'all' which will apply the hline to all the subplots or apply the traces to all the subplots which in your case is just the one subplot at (1,1). I'm only adding those arguments here to show you since it is not necessarily obvious what is going on in the background. Also worth noting that this will not work if you do not use a figure object with subplots. For example if you try to create the figure object without a (1,1) subplot such as with the following setup:
trace1 = go.Scatter(x=df["petal_length"], y=df["petal_width"], mode="markers")
trace2 = go.Scatter(y=np.arange(1, 7), mode="lines+markers", yaxis="y2")
data = [trace1, trace2]
layout = go.Layout(
yaxis=dict(title="yaxis1"),
yaxis2=dict(title="yaxis2 title", overlaying="y", side="right"))
fig = go.Figure(data=data, layout=layout)
fig.add_hline(y=2,line_dash="dash",line_color="Red",yref='y2')
this will not allow you to add an hline on the secondary y axis no matter what you do, it will always be on the primary y and this second example is absolutely a bug.
Upvotes: 0
Reputation: 19610
You may have found a bug in Plotly's add_hline
method! I can open a bug report for the Plotly team to look into.
For now, you can use the add_shape
method and set the parameters: xref="paper", x0=0, x0=1
to cover the entire width of the figure. Using yref="y2"
and setting both y0=2
to y1=2
works as expected.
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
# simple example with hline
df = px.data.iris()
fig = px.scatter(df, x="petal_length", y="petal_width")
fig.add_traces(go.Scatter(y=np.arange(1, 7), mode="lines+markers", yaxis='y2'))
## this may be a bug
# fig.add_hline(y=2, line_dash='dash', line_color='Red', yref='paper')
fig.add_shape(type="line",
xref="paper", yref="y2",
x0=0, y0=2, x1=1, y1=2,
line=dict(
color="red",
dash="dash"
),
)
fig.update_layout(
width=400,
height=400,
plot_bgcolor="white",
xaxis=dict(linecolor="black"),
yaxis=dict(linecolor="black"),
yaxis2=dict(
title="yaxis2 title",
overlaying="y",
side="right",
linecolor="black",
)
)
fig.update_xaxes(ticks="outside")
fig.update_yaxes(ticks="outside")
fig.show()
Upvotes: 2