Plotly垂直子图共用X轴:保留刻度标签并实现跨子图Spike Line
问题:保留X轴刻度同时实现跨子图Spike Line显示
我需要垂直堆叠多个共用X轴的图表,鼠标悬停时Spike Line能贯穿所有子图,同时希望统一悬浮提示显示所有子图数据。但根据Plotly的GitHub Issue,统一悬浮提示功能暂未纳入开发规划。
我编写了如下代码:
#!/usr/local/bin/python3 import plotly.graph_objects as go from plotly.subplots import make_subplots reference_distance = [0, 1, 2, 3, 4] compare_distance = [0, 1.5, 2.5, 3.5, 4.5] reference_time = [0, 1, 3, 5, 6] reference_speed = [100, 200, 300, 400, 500] compare_speed = [50, 100, 150, 200, 250] delta_t = [-1, -2, -3, -4, -5] base = [0] * len(delta_t) fig = go.Figure() fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0) fig.add_trace( go.Scatter( x=compare_distance, y=base, name='Reference Delta', hoverinfo='skip' ), row=1, col=1 ) fig.add_trace( go.Scatter( x=compare_distance, y=delta_t, name='Compare Delta', hovertemplate='Delta: %{y}<extra></extra>' ), row=1, col=1 ) fig.add_trace( go.Scatter( x=reference_distance, y=reference_speed, name='Reference', meta='Reference', hovertemplate='<b>%{meta}</b><br>Distance: %{x}<br>Speed: %{y}<extra></extra>' ), row=2, col=1 ) fig.add_trace( go.Scatter( x=compare_distance, y=compare_speed, name='Comapre', meta='Comapre', hovertemplate='<b>%{meta}</b><br>Distance: %{x}<br>Speed: %{y}<extra></extra>' ), row=2, col=1 ) fig.update_traces(mode="lines", xaxis="x") fig.update_xaxes( showspikes=True, spikecolor="grey", spikesnap="cursor", spikemode="across", hoverformat="none", ) fig.update_yaxes(title_text="Delta (Seconds)", row=1, col=1) fig.update_yaxes(title_text="Speed (MPH)", row=2, col=1) fig.update_layout( spikedistance=10000, hoverdistance=10000, hovermode="x unified", title="Delta T and Speed", xaxis_title="Distance (Miles)", legend_title="Runs" ) fig.show()
我发现只有在update_traces中添加xaxis="x"(xaxis="x1"效果相同)后,Spike Line才能覆盖所有子图,但这会导致X轴的刻度和标签消失。请问如何在保留X轴刻度与标签的同时,实现Spike Line跨所有子图显示?
- 无
xaxis="x"时的效果:Spike Line仅在当前子图显示,X轴刻度正常 - 有
xaxis="x"时的效果:Spike Line跨所有子图,但X轴刻度和标签消失
解决方案
问题根源是update_traces(xaxis="x")强制所有trace使用底层默认的x轴,覆盖了子图自动生成的x1(第二行)和x2(第一行)轴配置,导致共用X轴的刻度丢失。正确做法是利用子图共用X轴的特性,结合spike参数配置实现需求:
修改后的代码如下:
#!/usr/local/bin/python3 import plotly.graph_objects as go from plotly.subplots import make_subplots reference_distance = [0, 1, 2, 3, 4] compare_distance = [0, 1.5, 2.5, 3.5, 4.5] reference_time = [0, 1, 3, 5, 6] reference_speed = [100, 200, 300, 400, 500] compare_speed = [50, 100, 150, 200, 250] delta_t = [-1, -2, -3, -4, -5] base = [0] * len(delta_t) # 保留共用X轴配置 fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0) fig.add_trace( go.Scatter( x=compare_distance, y=base, name='Reference Delta', hoverinfo='skip' ), row=1, col=1 ) fig.add_trace( go.Scatter( x=compare_distance, y=delta_t, name='Compare Delta', hovertemplate='Delta: %{y}<extra></extra>' ), row=1, col=1 ) fig.add_trace( go.Scatter( x=reference_distance, y=reference_speed, name='Reference', meta='Reference', hovertemplate='<b>%{meta}</b><br>Distance: %{x}<br>Speed: %{y}<extra></extra>' ), row=2, col=1 ) fig.add_trace( go.Scatter( x=compare_distance, y=compare_speed, name='Compare', meta='Compare', hovertemplate='<b>%{meta}</b><br>Distance: %{x}<br>Speed: %{y}<extra></extra>' ), row=2, col=1 ) # 移除xaxis="x",仅保留线条模式设置 fig.update_traces(mode="lines") # 给所有X轴配置spike参数,共用X轴时仅最下方X轴显示刻度 fig.update_xaxes( showspikes=True, spikecolor="grey", spikesnap="cursor", spikemode="across", hoverformat="none", # 显式确保刻度可见 showticklabels=True ) fig.update_yaxes(title_text="Delta (Seconds)", row=1, col=1) fig.update_yaxes(title_text="Speed (MPH)", row=2, col=1) fig.update_layout( spikedistance=10000, hoverdistance=10000, hovermode="x unified", title="Delta T and Speed", xaxis_title="Distance (Miles)", legend_title="Runs" ) fig.show()
关键修改点:
- 移除
update_traces中的xaxis="x",避免覆盖子图自动生成的X轴配置 - 显式设置
update_xaxes(showticklabels=True),确保X轴刻度正常显示 - 利用
shared_xaxes=True和spikemode="across"的组合,让Spike Line自动贯穿所有共用X轴的子图 - 修正原代码中"Comapre"的拼写错误
修改后即可同时保留X轴刻度标签,实现Spike Line跨子图显示的效果。
内容的提问来源于stack exchange,提问作者av4625
相关产品推荐
相关产品推荐

