【问题标题】:Dynamically updating dropdown options with 2 Inputs in callback Dash在回调 Dash 中使用 2 个输入动态更新下拉选项
【发布时间】:2021-11-08 13:44:02
【问题描述】:

我被困在我想以两种方式更新批处理下拉列表的部分。如果在材料下拉列表中没有选择任何内容,则批次下拉列表应显示所有批次,但一旦选择了材料,它应更改为仅显示该材料类型的批次。

这是相关代码现在的样子:

import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output 
import plotly.express as px
import pandas as pd
import re

app = dash.Dash(__name__)

# Convert PARQUET to CSV


df = pd.read_csv("release_cln.csv")

# Store all unique values from Basis column

df_dis = df[df['Analysis_Name_CLN'].str.contains("Dissolution").fillna(False)]

df_dis['Batch'] = df_dis['Batch'].fillna(9999)
df_dis['Basis'] = df_dis['Batch'].fillna(9999)
df_dis['Material'] = df['Material'].fillna(9999)

batch = df_dis['Batch'].unique()
material = df_dis['Material'].unique()
basis = df_dis['Basis'].unique()

#[{'label': i, 'value': i} for i in material]

app.layout = html.Div([
    html.H1(children='Comparing Batches'),
    html.H2('Dissolution vs Timepoint'),

    # Batch 1 Dropdowns
    html.Div([
        html.Div(
            html.H3(children='''DP Batch''')
        ),
        html.Div([
            html.Div(children='''Batch: '''),
            dcc.Dropdown(
                    id='batch_dd',
                    multi=False,
                    clearable=True,
                    disabled=False
                ),
            ],style={'width': '20%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Material: '''),
            dcc.Dropdown(
                    id='material_dd',
                    multi=False,
                    clearable=True,
                    disabled=False
                ),
            ],style = {'width': '15%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Basis: '''),
            dcc.Dropdown(
                    id='basis_dd',
                    multi=False,
                    clearable=True,
                    disabled=False
                ),
            ],style = {'width': '15%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Variant: '''),
            dcc.Dropdown(
                    id='variant_dd',
                    multi=False,
                    clearable=True,
                    disabled=False
                ),
            ],style = {'width': '10%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Analysis: '''),
            dcc.Dropdown(
                    id='analysis_name_dd',
                    multi=False,
                    clearable=True,
                    disabled=False,
                    options=[]
                ),
            ],style = {'width': '40%','display': 'inline-block'}
        )
        ],style = {'width': '90%', 'display': 'inline-block'}
    ),

    html.Br(),

    # Batch 2 Dropdowns
    html.Div([
        html.Div(
            html.H3(children='''DS Batch''')
        ),
        html.Div([
            html.Div(children='''Batch: '''),
            dcc.Dropdown(
                    id='batch_dd_1',
                    multi=False,
                    clearable=True,
                    disabled=False,
                    options=[{'label': i, 'value': i} for i in batch]
                ),
            ],style={'width': '20%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Material: '''),
            dcc.Dropdown(
                    id='material_dd_1',
                    multi=False,
                    clearable=True,
                    disabled=False,
                    options=[],
                ),
            ],style = {'width': '15%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Basis: '''),
            dcc.Dropdown(
                    id='basis_dd_1',
                    multi=False,
                    clearable=True,
                    disabled=False,
                    options=[]
                ),
            ],style = {'width': '15%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Variant: '''),
            dcc.Dropdown(
                    id='variant_dd_1',
                    multi=False,
                    clearable=True,
                    disabled=False,
                    options=[]
                ),
            ],style = {'width': '10%','display': 'inline-block'}
        ),
        html.Div([
            html.Div(children='''Analysis: '''),
            dcc.Dropdown(
                    id='analysis_name_dd_1',
                    multi=False,
                    clearable=True,
                    disabled=False,
                    options=[]
                ),
            ],style = {'width': '40%','display': 'inline-block'}
        )
        ],style = {'width': '90%', 'display': 'inline-block'}
    ),

    html.Br(),
    dcc.Graph(id='dissol_tp')
])

## Batch 1 Dropdowns
#Call back to update Batch options if user searches for Batches
@app.callback(
    Output('batch_dd','options'),
    [Input('batch_dd','search_value'),
    Input('material_dd','value')]
)
def batch_options(search_value, material_dd):
    if material_dd is None:
        return [{'label': i, 'value': i} for i in batch]
    else:
        batch_df = df[df['Material']==material_dd]
        return [{'label':i,'value':i} for i in batch_df['Batch'].fillna('None').unique()]


@app.callback(
    Output('material_dd','options'),
    Input('material_dd','search_value'))
def material_options(search_value):
    return [{'label': i, 'value': i} for i in material]

# Callback to select default value in basis list
@app.callback(
    Output('basis_dd','options'),
    Input('basis_dd','search_value'))
def variant_default(batch_dd):
    return [k['value'] for k in batch_dd]

# Chained callback to select variants with the selected batch
@app.callback(
    Output('variant_dd','options'),
    Input('batch_dd','value'))
def get_variant(batch_dd):
    batch_df = df[df['Batch']==batch_dd]
    return [{'label':i,'value':i} for i in batch_df['Variant'].fillna('None').unique()]


当前发生的情况是批次下拉列表显示所有批次值,即使选择了材料值并且不会动态更改

【问题讨论】:

  • 缺少 'material_dd' 的选项,它们似乎是静态的,不像 'batch_dd',因此您可以通过在相应的 dcc.Dropdown 中添加 options=[{'label':i,'value':i} for i in material] 在 app.layout 中直接定义它们。
  • 我添加了一个回调来更新材料下拉列表,我会更新问题。目前发生的情况是,批次正在更新所有值,当我选择任何材料时没有任何反应
  • 我建议创建一个最小的示例来重现问题并且可以按原样运行,从而更容易调试。在您共享的代码中,顺便说一句,您没有正确导入 dash_html_componentsdash_core_components
  • 尝试从batch_options回调中删除Input('batch_dd','search_value')(未使用)。可能是更新 'batch_dd' 选项会触发同一组件的 'search_value' 事件,在这种情况下,您使用 'search_value' 为 'batch_dd' 重新输入相同的回调(即使它是无),但没有值'material_dd'(因为只有一个组件触发回调)。如果您打算同时使用批量 search_value 和 material_dd 值作为输入,则需要检查 material_dd 的State 以获取实际值。

标签: python pandas plotly-dash


【解决方案1】:

这是一个基于您的代码的演示,只是展示了如何让批次下拉列表动态依赖于材料下拉列表中选择的任何内容。

import random
import dash
import numpy as np
import pandas as pd

from dash import dcc
from dash import html
from dash.dependencies import Input
from dash.dependencies import Output


app = dash.Dash(__name__)

# Convert PARQUET to CSV
# df = pd.read_csv("release_cln.csv")

n = 50
df_dis = pd.DataFrame(
    {
        "Batch": np.random.randint(1, 2000, n),
        "Material": random.choices(
            ["wood", "metal", "fire", "water", "ice", "rock"], k=n
        ),
    }
)

batches = {
    m: list(df_dis[df_dis.Material == m].Batch.values)
    for m in df_dis.Material
}


batch = df_dis["Batch"].unique()
material = df_dis["Material"].unique()


app.layout = html.Div(
    [
        html.H1(children="Comparing Batches"),
        html.H2("Dissolution vs Timepoint"),
        # Batch 1 Dropdowns
        html.Div(
            [
                html.Div(html.H3(children="""DP Batch""")),
                html.Div(
                    [
                        html.Div(children="""Material: """),
                        dcc.Dropdown(
                            id="material_dd",
                            multi=False,
                            clearable=True,
                            disabled=False,
                        ),
                    ],
                    style={"width": "15%", "display": "inline-block"},
                ),
                html.Div(
                    [
                        html.Div(children="""Batch: """),
                        dcc.Dropdown(
                            id="batch_dd",
                            multi=False,
                            clearable=True,
                            disabled=False,
                        ),
                    ],
                    style={"width": "20%", "display": "inline-block"},
                ),
            ]
        ),
    ]
)

## Batch 1 Dropdowns
# Call back to update Batch options if user searches for Batches
@app.callback(
    Output("batch_dd", "options"),
    [Input("batch_dd", "search_value"), Input("material_dd", "value")],
)
def batch_options(search_value, material_dd):
    if material_dd is None:
        return [{"label": i, "value": i} for i in batch]
    else:
        return [{"label": i, "value": i} for i in batches[material_dd]]


@app.callback(
    Output("material_dd", "options"), Input("material_dd", "search_value")
)
def material_options(search_value):
    return [{"label": i, "value": i} for i in material]


if __name__ == "__main__":
    app.run_server(debug=True, dev_tools_hot_reload=True)

这就是我所做的:

  • 创建一个字典,其中数据框中的每个唯一材料构成键,并且每个材料都有一个相应的列表(假设所有可能的材料值在 df 中具有 >1 行),特别是具有所选材料类型的批次。
  • 同样,您将继续进一步嵌套下拉菜单?

【讨论】:

    猜你喜欢
    • 2022-08-08
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-01
    相关资源
    最近更新 更多