You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现同一DataFrame不同轴范围多子图的缩放联动?

实现Plotly子图基于关联数据的缩放联动

要实现两个子图的缩放联动(不共享轴),可以通过监听第一个图的布局变化事件,筛选对应的数据后更新第二个图的轴范围。以下提供两种可行方案:

方案1:纯Plotly + 自定义JavaScript回调(适合静态HTML/Jupyter)

这种方案无需额外框架,直接在Plotly图表中嵌入JS逻辑,适合导出静态HTML或在Jupyter Notebook中使用:

import plotly.subplots as subplots
import pandas as pd
import plotly.graph_objects as go

df = pd.DataFrame({
    'a': [1, 2, 3, 4, 5],
    'b': [10, 15, 13, 17, 20],
    'c': [2, 3, 4, 5, 6],
    'd': [8, 12, 10, 14, 16],
    'time': [1, 2, 3, 4, 5]
})

# 创建子图并添加轨迹
fig = subplots.make_subplots(rows=2, cols=1, subplot_titles=("A vs B", "C vs D"))
fig.add_trace(go.Scatter(x=df['a'], y=df['b'], mode='markers+lines'), row=1, col=1)
fig.add_trace(go.Scatter(x=df['c'], y=df['d'], mode='markers+lines'), row=2, col=1)

# 给轴设置唯一ID,方便JS回调定位
fig.update_xaxes(id='x1', row=1, col=1)
fig.update_xaxes(id='x2', row=2, col=1)
fig.update_yaxes(id='y2', row=2, col=1)

# 添加自定义JS联动逻辑
fig.update_layout(
    js_on_change="""
        function(gd) {
            // 获取第一个图的x轴当前范围
            const xRange = gd.layout.xaxis.range;
            if (!xRange) return;
            
            // 加载原始数据
            const data = """ + df.to_json(orient='records') + """;
            
            // 筛选出第一个图可见范围内的数据点
            const filteredPoints = data.filter(row => row.a >= xRange[0] && row.a <= xRange[1]);
            if (filteredPoints.length === 0) return;
            
            // 计算第二个图需要展示的c、d轴范围(加5%边距避免点贴边)
            const cVals = filteredPoints.map(p => p.c);
            const dVals = filteredPoints.map(p => p.d);
            const cMargin = (Math.max(...cVals) - Math.min(...cVals)) * 0.05 || 0.1;
            const dMargin = (Math.max(...dVals) - Math.min(...dVals)) * 0.05 || 0.1;
            
            // 更新第二个图的轴范围
            Plotly.relayout(gd, {
                'xaxis2.range': [Math.min(...cVals) - cMargin, Math.max(...cVals) + cMargin],
                'yaxis2.range': [Math.min(...dVals) - dMargin, Math.max(...dVals) + dMargin]
            });
        }
    """
)

fig.show()

逻辑说明

  1. 监听第一个图的布局变化(缩放、平移都会触发)
  2. 根据第一个图的x轴范围筛选对应的数据点
  3. 计算筛选后数据中c和d的最值,加入小边距后更新第二个图的轴范围
  4. 保留两个子图各自的刻度体系,避免共享轴导致的可读性问题

方案2:Dash框架实现Python回调(适合Web应用)

如果需要构建交互式Web应用,用Dash的Python回调更灵活,无需写JS:

import dash
from dash import dcc, html, Input, Output, State
import pandas as pd
import plotly.graph_objects as go

df = pd.DataFrame({
    'a': [1, 2, 3, 4, 5],
    'b': [10, 15, 13, 17, 20],
    'c': [2, 3, 4, 5, 6],
    'd': [8, 12, 10, 14, 16],
    'time': [1, 2, 3, 4, 5]
})

app = dash.Dash(__name__)

# 页面布局
app.layout = html.Div([
    dcc.Graph(id='plot-a-b', figure=go.Figure(
        data=[go.Scatter(x=df['a'], y=df['b'], mode='markers+lines')],
        layout=go.Layout(title="A vs B")
    )),
    dcc.Graph(id='plot-c-d', figure=go.Figure(
        data=[go.Scatter(x=df['c'], y=df['d'], mode='markers+lines')],
        layout=go.Layout(title="C vs D")
    ))
])

# 联动回调
@app.callback(
    Output('plot-c-d', 'figure'),
    Input('plot-a-b', 'relayoutData'),
    State('plot-c-d', 'figure')
)
def update_cd_plot(relayout_data, cd_fig):
    # 初始状态或无缩放操作时返回原图表
    if not relayout_data or 'xaxis.range[0]' not in relayout_data:
        return cd_fig
    
    # 获取第一个图的x轴范围
    x_min = relayout_data['xaxis.range[0]']
    x_max = relayout_data['xaxis.range[1]']
    
    # 筛选对应数据
    filtered_df = df[(df['a'] >= x_min) & (df['a'] <= x_max)]
    if filtered_df.empty:
        return cd_fig
    
    # 计算轴范围并添加边距
    c_min, c_max = filtered_df['c'].min(), filtered_df['c'].max()
    d_min, d_max = filtered_df['d'].min(), filtered_df['d'].max()
    c_margin = (c_max - c_min) * 0.05 if c_max != c_min else 0.1
    d_margin = (d_max - d_min) * 0.05 if d_max != d_min else 0.1
    
    # 更新第二个图的轴范围
    cd_fig['layout']['xaxis']['range'] = [c_min - c_margin, c_max + c_margin]
    cd_fig['layout']['yaxis']['range'] = [d_min - d_margin, d_max + d_margin]
    
    return cd_fig

if __name__ == '__main__':
    app.run_server(debug=True)

适用场景

  • 适合需要后端数据处理、用户认证等复杂逻辑的Web应用
  • 全程用Python编写,无需掌握JavaScript

内容的提问来源于stack exchange,提问作者K L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 17:51:07