You need to enable JavaScript to run this app. 如何在Dash中通过回调实现联动更新的双列并排子图
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dash中通过回调实现联动更新的双列并排子图

问题根因
  • 直接在回调返回的data数组中新增trace时,所有轨迹默认绑定到全局的第一组x/y坐标轴,不会自动拆分到独立子图,因此会出现全部轨迹堆叠在同一坐标系的效果
  • 即便引入make_subplots,如果没有通过显式的行列参数将trace绑定到对应子图,或者手动设置trace的坐标轴指向(如xaxis='x2'、yaxis='y2'),依然无法实现分栏渲染的效果
实现方案
  • 用make_subplots初始化1行2列的独立子图画布
  • 遍历选中ID的分组数据时,对每一组数据分别生成两类轨迹:x_val与y_val的散点图绑定到第一列子图,x_val与rand的散点图绑定到第二列子图
  • 统一更新布局参数,匹配坐标轴标题、画布尺寸要求

补充:如果不使用make_subplots工具,手动实现双坐标系分栏的话,需要在trace中显式指定坐标轴绑定关系(如xaxis='x2'、yaxis='y2'),同时在layout中定义第二组坐标轴的位置、标题参数,这种方式手动维护成本较高,容易出现绑定错误,优先推荐用make_subplots实现子图布局。

可直接运行的完整代码
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import pandas as pd
from plotly.subplots import make_subplots
import plotly.graph_objects as go

# 初始化数据集
df = pd.DataFrame(
    [['A', 1, 7, 10], ['A', 2, 6, 15], ['A', 3, 14, 20],
     ['B', 1, 3, 2], ['B', 2, 9, 6], ['B', 3, 2, 8],
     ['C', 1, 1, 90], ['C', 2, 5, 40], ['C', 3, 11, 23]],
    columns=['ID', 'x_val', 'y_val', 'rand']
)

app = dash.Dash()

app.layout = html.Div([
    dcc.Dropdown(
        id='my-dropdown',
        options=[{'label': i, 'value': i} for i in df.ID.unique()],
        multi=True,
        placeholder='Select id',
        value=[df.ID.min()]
    ),
    dcc.Graph(id='my-graph')
], style={'width': '800px'})  # 调整容器宽度匹配子图画布尺寸

@app.callback(Output('my-graph', 'figure'), [Input('my-dropdown', 'value')])
def update_graph(selected_dropdown_value):
    # 按选中ID筛选并分组数据
    filtered_df = df[df['ID'].isin(selected_dropdown_value)]
    grouped_df = filtered_df.groupby(by=['ID'])

    # 初始化1行2列的子图画布,附带子图标题
    fig = make_subplots(
        rows=1, cols=2,
        subplot_titles=("y_val 随x_val变化", "rand 随x_val变化")
    )

    for ID, group in grouped_df:
        # 添加第一列子图的轨迹:x_val vs y_val
        fig.add_trace(
            go.Scatter(
                x=group['x_val'],
                y=group['y_val'],
                name=f"{ID} - y_val"
            ),
            row=1, col=1
        )
        # 添加第二列子图的轨迹:x_val vs rand
        fig.add_trace(
            go.Scatter(
                x=group['x_val'],
                y=group['rand'],
                name=f"{ID} - rand"
            ),
            row=1, col=2
        )

    # 统一更新布局参数
    fig.update_layout(
        height=600,
        width=800,
        title_text="Side By Side Subplots"
    )
    # 设置坐标轴标题
    fig.update_xaxes(title_text="X-title", row=1, col=1)
    fig.update_yaxes(title_text="Y-title", row=1, col=1)
    fig.update_yaxes(title_text="Rand值", row=1, col=2)
    fig.update_xaxes(title_text="X-title", row=1, col=2)

    return fig

if __name__ == '__main__':
    app.run_server()
效果验证
  • 下拉框选择任意多个ID后,回调会自动将对应数据拆分渲染到两个并排子图中:左侧子图展示y_val随x_val的变化趋势,右侧子图展示rand值随x_val的变化趋势
  • 每个ID对应的两个子图轨迹会通过图例标识,不会出现全部轨迹堆叠在同一坐标系的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.06 05:54:03