Plotly多y轴图表如何实现点击曲线时动态显隐对应关联坐标轴
可以实现,核心思路是监听图例点击事件,将trace的显隐状态和对应y轴的显隐状态绑定。下面分两种常用场景给出实现方案:
方案1:生成独立HTML文件(无需后端,纯前端交互)
这个方案通过注入JavaScript事件监听代码实现,不需要额外的服务支撑,生成的HTML可以直接打开使用。
import plotly.graph_objects as go from plotly.subplots import make_subplots # 创建带双y轴的画布 fig = make_subplots(specs=[[{"secondary_y": True}]]) # 添加轨迹,注意每个轨迹对应yaxis属性,默认第一个是'y',第二个是'y2' fig.add_trace( go.Scatter(x=[1, 2, 3], y=[40, 50, 60], name="yaxis data"), secondary_y=False, ) fig.add_trace( go.Scatter(x=[2, 3, 4], y=[4, 5, 6], name="yaxis2 data"), secondary_y=True, ) # 基础配置 fig.update_layout( title_text="双Y轴同步显隐示例", xaxis_title="x轴标题", yaxis_title="<b>主</b>y轴标题", yaxis2_title="<b>次</b>y轴标题" ) # 注入JavaScript实现同步显隐逻辑 js_code = """ const plotlyElement = document.getElementById('{plot_id}'); plotlyElement.on('plotly_restyle', function(data) { const update = {}; // 统计每个y轴下是否存在可见轨迹 const axisVisibleMap = {}; plotlyElement.data.forEach(trace => { const yAxisKey = trace.yaxis || 'y'; const isTraceVisible = trace.visible !== 'legendonly' && trace.visible !== false; axisVisibleMap[yAxisKey] = axisVisibleMap[yAxisKey] || isTraceVisible; }); // 批量更新y轴显隐状态 Object.keys(axisVisibleMap).forEach(key => { update[`${key}.visible`] = axisVisibleMap[key]; }); Plotly.relayout(plotlyElement, update); }); """ # 将JS代码添加到图中 fig.add_js_funcs(js_code) # 生成HTML文件或者直接显示 fig.write_html("multi_y_sync.html") fig.show()
如果是3个及以上y轴的情况,只需要在创建子图的时候定义好对应的y轴,添加轨迹时指定yaxis参数对应到'y3'、'y4'即可,上面的JS逻辑可以自动适配,不需要修改。
方案2:Dash应用场景
如果是在Dash框架中开发交互式应用,可以直接用Python回调实现,不需要写JS:
from dash import Dash, dcc, html, Input, Output, State, callback import plotly.graph_objects as go from plotly.subplots import make_subplots app = Dash(__name__) # 初始化图表 def init_fig(): fig = make_subplots(specs=[[{"secondary_y": True}]]) fig.add_trace( go.Scatter(x=[1, 2, 3], y=[40, 50, 60], name="yaxis data"), secondary_y=False, ) fig.add_trace( go.Scatter(x=[2, 3, 4], y=[4, 5, 6], name="yaxis2 data"), secondary_y=True, ) fig.update_layout( title_text="双Y轴同步显隐示例", xaxis_title="x轴标题", yaxis_title="<b>主</b>y轴标题", yaxis2_title="<b>次</b>y轴标题" ) return fig app.layout = html.Div([ dcc.Graph(id="multi-y-graph", figure=init_fig()) ]) @callback( Output("multi-y-graph", "figure"), Input("multi-y-graph", "restyleData"), State("multi-y-graph", "figure"), prevent_initial_call=True ) def sync_y_axis(restyle_data, fig): traces = fig['data'] layout = fig['layout'] # 统计每个y轴下是否有可见的轨迹 y_axis_visibility = {} for trace in traces: y_key = trace.get('yaxis', 'y') visible = trace.get('visible', True) is_visible = visible not in ('legendonly', False) y_axis_visibility[y_key] = y_axis_visibility.get(y_key, False) or is_visible # 更新布局 for y_key, visible in y_axis_visibility.items(): axis_key = y_key if y_key.startswith('yaxis') else f"{y_key}axis" if axis_key in layout: layout[axis_key]['visible'] = visible return fig if __name__ == "__main__": app.run_server(debug=True)
注意事项
- 如果多个轨迹绑定同一个y轴,上面的逻辑会自动判断:只有该y轴下所有轨迹都被隐藏时,y轴才会隐藏,只要有一个轨迹显示,y轴就保持显示
- 3个及以上y轴的场景,只需要在创建图表时正确配置每个轨迹对应的
yaxis参数即可,逻辑无需调整
内容的提问来源于stack exchange,提问作者jim
相关产品推荐
相关产品推荐

