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

Python Plotly交互式图表:将下拉菜单替换为可搜索输入框

问题描述

我想将现有Plotly交互式图表的下拉按钮替换为输入框,实现输入项目名称前缀即可搜索并选择对应选项的功能。目前我已实现支持单选单个项目或全选所有项目的下拉菜单,但希望用户可以通过输入项目名称关键词,点击选择对应项目即可展示对应的图表。我刚接触Plotly,非常感谢大家提供的任何建议。

当前实现的效果图如下:
效果图

我的代码如下:

def interactive_multi_plot(actual, forecast_1, forecast_2, title, addAll = True):
    fig = go.Figure()
    
    for column in forecast_1.columns.to_list():
        fig.add_trace(
            go.Scatter(
                x = forecast_1.index,
                y = forecast_1[column],
                name = "Forecast_SI"
            )
        )
    
        button_all = dict(label = 'All',
                      method = 'update',
                      args = [{'visible': forecast_1.columns.isin(forecast_1.columns),
                               'title': 'All',
                               'showlegend':True}])
    
    for column in forecast_2.columns.to_list():
        fig.add_trace(
            go.Scatter(
                x = forecast_2.index,
                y = forecast_2[column],
                name = "Forecast_LSTM" 
            )
        )
    
        button_all = dict(label = 'All',
                      method = 'update',
                      args = [{'visible': forecast_2.columns.isin(forecast_2.columns),
                               'title': 'All',
                               'showlegend':True}])
    for column in actual.columns.to_list():
        fig.add_trace(
            go.Scatter(
                x = actual.index,
                y = actual[column],
                name = "True values" 
            )
        )
    
        button_all = dict(label = 'All',
                      method = 'update',
                      args = [{'visible': actual.columns.isin(actual.columns),
                               'title': 'All',
                               'showlegend':True}])
    
    fig.layout.plot_bgcolor = '#010028'
    fig.layout.paper_bgcolor = '#010028'
    def create_layout_button(column):
        return dict(label = column,
                    method = 'update',
                    args = [{'visible': actual.columns.isin([column]),
                             'title': column,
                             'showlegend': True}])
    fig.update_layout(
        updatemenus=[go.layout.Updatemenu(
            active = 0,
            buttons = ([button_all] * addAll) +  list(actual.columns.map(lambda column: create_layout_button(column)))
            )
        ]     
    )
    # Update remaining layout properties
    fig.update_layout(
        title_text=title,
        height=800,
        font = dict(color='#fff', size=12)
    )
    
    fig.show()

运行后得到的错误提示如下:
错误截图


解决方案

原生Plotly的内置下拉菜单不支持搜索功能,要实现输入关键词搜索选择项目的效果,有两种可行方案:

方案1:使用Dash框架实现(推荐,可完美满足搜索需求)

Dash是Plotly官方推出的交互式Web应用框架,自带支持搜索的下拉选择组件,无需复杂开发即可实现需求:

  • 直接使用dcc.Dropdown组件,默认开启搜索匹配功能,输入关键词会自动过滤匹配的项目选项
  • 通过组件回调绑定选中值,动态更新图表展示内容即可
    核心示例代码:
import dash
from dash import dcc, html, Input, Output
import plotly.graph_objects as go

# 初始化应用
app = dash.Dash(__name__)
project_list = actual.columns.tolist()

# 页面布局
app.layout = html.Div([
    dcc.Dropdown(
        id='project-selector',
        options=[{'label': '所有项目', 'value': 'all'}] + [{'label': p, 'value': p} for p in project_list],
        value='all',
        placeholder='输入项目名称关键词搜索',
        searchable=True
    ),
    dcc.Graph(id='forecast-graph')
])

# 回调更新图表
@app.callback(
    Output('forecast-graph', 'figure'),
    Input('project-selector', 'value')
)
def update_graph(selected_project):
    fig = go.Figure()
    if selected_project == 'all':
        # 渲染所有项目的3类数据
        for col in actual.columns:
            fig.add_trace(go.Scatter(x=actual.index, y=actual[col], name='真实值'))
            fig.add_trace(go.Scatter(x=forecast_1.index, y=forecast_1[col], name='Forecast_SI'))
            fig.add_trace(go.Scatter(x=forecast_2.index, y=forecast_2[col], name='Forecast_LSTM'))
        fig.update_layout(title='所有项目预测对比')
    else:
        # 仅渲染选中项目的3类数据
        fig.add_trace(go.Scatter(x=actual.index, y=actual[selected_project], name='真实值'))
        fig.add_trace(go.Scatter(x=forecast_1.index, y=forecast_1[selected_project], name='Forecast_SI'))
        fig.add_trace(go.Scatter(x=forecast_2.index, y=forecast_2[selected_project], name='Forecast_LSTM'))
        fig.update_layout(title=f'{selected_project} 预测对比')
    # 复用原有样式配置
    fig.update_layout(
        plot_bgcolor='#010028',
        paper_bgcolor='#010028',
        font = dict(color='#fff', size=12),
        height=800
    )
    return fig

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

方案2:修复现有代码报错(仅保留下拉选择功能,不支持搜索)

现有代码的报错是因为button_all在循环中被多次覆盖,生成的visible数组长度和实际trace数量不匹配导致,每个项目对应3条trace(真实值、SI预测、LSTM预测),需要调整visible数组的生成逻辑:

def interactive_multi_plot(actual, forecast_1, forecast_2, title, addAll = True):
    fig = go.Figure()
    total_cols = len(actual.columns)
    # 先按项目维度添加trace,保证每个项目的3条trace连续
    for idx, column in enumerate(actual.columns):
        fig.add_trace(
            go.Scatter(x=actual.index, y=actual[column], name="True values")
        )
        fig.add_trace(
            go.Scatter(x=forecast_1.index, y=forecast_1[column], name="Forecast_SI")
        )
        fig.add_trace(
            go.Scatter(x=forecast_2.index, y=forecast_2[column], name="Forecast_LSTM")
        )
    # 构造全选按钮
    button_all = dict(label = 'All',
                  method = 'update',
                  args = [{'visible': [True]*3*total_cols,
                           'title': 'All',
                           'showlegend':True}])
    # 构造单个项目按钮
    def create_layout_button(column, col_index):
        visible = [False] * 3 * total_cols
        visible[col_index*3] = True
        visible[col_index*3 + 1] = True
        visible[col_index*3 + 2] = True
        return dict(label = column,
                    method = 'update',
                    args = [{'visible': visible,
                             'title': column,
                             'showlegend': True}])
    # 更新布局
    fig.update_layout(
        updatemenus=[go.layout.Updatemenu(
            active = 0,
            buttons = ([button_all] * addAll) +  [create_layout_button(col, i) for i, col in enumerate(actual.columns)]
            )
        ],
        plot_bgcolor = '#010028',
        paper_bgcolor = '#010028',
        title_text=title,
        height=800,
        font = dict(color='#fff', size=12)
    )
    fig.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 22:21:00