I am currently attempting to draw a unified spike across multiple subplots when hovering. I want to do this to improve the visualization of the x-axis. I am currently following advice from this thread on GitHub.
However, when I try to do it, the x-axis immediately glitches out and shoves all the data to the far right of the chart. Could anyone more familiar with Plotly explain why this is happening? I have included a reproducible piece of code below.
Note: In order to see the visual bug, you have to uncomment the problematic lines
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from datetime import date
trace1 = go.Scatter(x=[date(2023, 1, 15), date(2023, 2, 15), date(2023, 3, 15), date(2023, 4, 15),
date(2023, 5, 15), date(2023, 6, 15), date(2023, 7, 15), date(2023, 8, 15),
date(2023, 9, 15), date(2023, 10, 15), date(2023, 11, 15), date(2023, 12, 15)],
y=[1000, 2000, 3000, 4000,
5000, 6000, 7000, 8000,
9000, 10000, 11000, 12000],
name='trace1')
trace2 = go.Scatter(x=[date(2023, 1, 15), date(2023, 2, 15), date(2023, 3, 15), date(2023, 4, 15),
date(2023, 5, 15), date(2023, 6, 15), date(2023, 7, 15), date(2023, 8, 15),
date(2023, 9, 15), date(2023, 10, 15), date(2023, 11, 15), date(2023, 12, 15)],
y=[10_000, 20_000, 30_000, 40_000,
50_000, 60_000, 70_000, 80_000,
90_000, 100_000, 110_000, 120_000],
name='trace2')
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.02)
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2, row=2, col=1)
fig.add_annotation(
xref='x domain',
yref='y domain',
x=0,
y=1,
text='FIRST ANNOTATION',
showarrow=False,
font=dict(size=14, color='blue'),
row=1, col=1
)
fig.add_annotation(
xref='x domain',
yref='y domain',
x=0,
y=1,
text='SECOND ANNOTATION',
showarrow=False,
font=dict(size=14, color='red'),
row=2, col=1
)
# fig.update_traces(xaxis='x')
# fig.update_xaxes(spikemode='across+marker')
# fig.update_shapes(selector=dict(type="line"), xref="x domain")
# fig.update_shapes(selector=dict(type="rect"), xref="x")
fig.update_layout(height=600, width=600, title_text='Example Chart')
fig.show()
I don't know really why this is happening but it turns out that the x axes (auto)ranges are not computed correctly when we make both traces refer to the same xaxis with fig.update_traces(xaxis='x')
. To fix that, we need to set the proper range manually. Also instead of 'x'
, we need to refer to 'x2'
, that is, the x axis of the 2nd row, otherwise we loose the date ticks.
Doing the above will make the first annotation disappear, but again we can fix that by setting its xref
to 'x2 domain'
(instead of 'x'). The weird thing is doing that via fig.add_annotation()
has no effect (I guess because references to x and/or y are overridden automatically to match the axis id of the subplot corresponding to the specified row
and col
), so we have to assign the value manually.
Replacing the commented lines with what follows works correctly :
# The main xaxis is 'x2'
fig.update_traces(xaxis='x2')
fig['layout']['annotations'][0]['xref'] = 'x2 domain'
# Compute xaxes date range
d0, d1 = min(trace1.x), max(trace1.x)
room = (d1 - d0) * 0.07
d0 -= room
d1 += room
fig.update_xaxes(spikemode='across+marker', type='date', range=[d0, d1])