为动态下拉列表正确设置回调 [英] Properly setting up callbacks for dynamic dropdowns plotly dash

查看:71
本文介绍了为动态下拉列表正确设置回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个 Dash 仪表板,其中一个框中的下拉选项取决于上一个下拉选择.

数据由两个字典组成,每个字典有两个键.每个键都包含一个带有几列的数据框.确切数据:

from jupyter_dash import JupyterDash将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html从 dash.dependencies 导入输入、输出、状态、ClientsideFunction将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html将熊猫导入为 pd导入 plotly.graph_objs as go从 dash.dependencies 导入输入,输出将 dash_bootstrap_components 导入为 dbc将 numpy 导入为 np从 plotly.subplots 导入 make_subplots导入 plotly.express 作为 px将熊猫导入为 pd从熊猫进口时间戳将 numpy 导入为 npdf_vals_prod={'corn':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),2:时间戳('2020-09-23 12:00:00'),3:时间戳('2020-09-23 18:00:00'),4:时间戳('2020-09-24 00:00:00')},'2m_temp_prod':{1:0.020584322444347606,2:0.08973907730395358,3:2.3866310395722463,4:3.065472457668321},'total_precip_prod':{1:1.372708470272411,2:2.135683294556938,3:1.9811172016307312,4: 2.1082116841869323}}),'大豆':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),2:时间戳('2020-09-23 12:00:00'),3:时间戳('2020-09-23 18:00:00'),4:时间戳('2020-09-24 00:00:00')},'2m_temp_prod':{1:0.6989001827317545,2:-0.8699121426411993,3:-0.9484359259520706,4:0.7391299158393124},'total_precip_prod':{1:-0.07639291299336869,2:0.19182892415959496,3:0.8719339093510236,4:0.90586956349059}})}df_vals_area={'corn':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),2:时间戳('2020-09-23 12:00:00'),3:时间戳('2020-09-23 18:00:00'),4:时间戳('2020-09-24 00:00:00')},'2m_temp_area':{1:-1.6820417878457192,2:-0.2856437053872421,3:0.3864022581278122,4:0.5873739667356371},'total_precip_area':{1:1.3703311242708185,2:0.25528434511264525,3:0.5007488191835624,4:-0.16292114222272375}}),'大豆':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),2:时间戳('2020-09-23 12:00:00'),3:时间戳('2020-09-23 18:00:00'),4:时间戳('2020-09-24 00:00:00')},'2m_temp_area':{1:1.3789989862086967,2:-0.7797086923820608,3:1.0695635889750523,4:1.136561500804678},'total_precip_area':{1:-0.6035111830104833,2:-0.18237330469451313,3:-0.7820158376898607,4:-0.6117188028872137}})}app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])weight_opts=['生产','面积']控件 = dbc.Card([ dbc.FormGroup([dbc.Label(裁剪"),dcc.Dropdown(id=作物",选项=[{"label": col, "value": col} 用于列表中的 col(df_vals_prod.keys())],值=列表(df_vals_prod.keys())[0],可清除=假,),]),dbc.FormGroup([dbc.Label(权重"),dcc.Dropdown(id=权重",选项=[{label": i, value": i} for i in weight_opts],值=weight_opts[0],可清除=假,),]),dbc.FormGroup([dbc.Label(预测变量"),dcc.Dropdown(id="forecast_v",),]),],身体=真,)app.layout = dbc.Container([html.hr(),dbc.Row([dbc.Col([dbc.Row([dbc.Col(控件)],对齐=开始"),dbc.Row([dbc.Col([html.Br(),dbc.Row([dbc.Col([html.Div(id = 'txt1')])]),html.Br(),dbc.Row([dbc.Col([html.Div(id = 'txt2')])])])])],xs = 2),dbc.Col([dbc.Row([dbc.Col([html.Div(id = 'plot_title')],)]),dbc.Row([dbc.Col(dcc.Graph(id="crop-graph")),#dbc.Col(dcc.Graph(id="cluster-graph"))])])],),],流体=真,)@app.callback(输出('forecast_v','options'),[输入('权重','价值')])def update_var_dropdown(weight):如果重量=='生产':返回 [{'label': i, 'value': i} for i in df_vals_prod['corn'].columns[1:]]elif 重量=='面积':返回 [{'label': i, 'value': i} for i in df_vals_area['corn'].columns[1:]]@app.callback(输出(裁剪图",图"),[输入(裁剪",值"),输入(权重",值"),输入(forecast_v",值"),],)defcrop_graph(Crop, val, weight):# plotly图形设置fig = make_subplots(specs=[[{secondary_y": True}]])如果体重:fig.add_trace(go.Scatter(name=val, x=df_vals_prod[Crop]['time'], y=((df_vals_prod[Crop][val]-273)*(9/5))+32,模式='线', line=dict(color='red', width=4),hovertemplate='Date: %{x|%d %b %H%M} UTC
Temp: %{y:.2f} F'), secondary_y=False,)fig.update_yaxes(title_text="<b>Temp (F)<b>", color='red', secondary_y=False,)fig.update_yaxes(title_text=<b>24hr Forecast Change (F)</b>", secondary_y=True)返回(图)app.run_server(mode='external', port = 8099)

如您所见,此 6 小时数据旨在绘制为时间序列.现在我想添加几个下拉菜单.第一个下拉列表 (Crop) 选择要选择的作物(玉米或大豆),这是每个字典中的两个键.

第二个下拉列表(权重)现在选择我们要使用的数据帧.用户在第二个下拉列表中选择的内容将决定要在第三个下拉列表中选择的选项.

第三个下拉列表将选择实际变量(预测变量),它是每个数据框中可用的两列之一.因此,如果在下拉列表 2 中,Production"被选中,下拉列表 3 的选项将包括2m_temp_prod"或total_precip_prod".对于区域"在下拉列表 2 中,下拉列表 3 的选项是2m_temp_area"或total_precip_area".

这是我到目前为止的代码.我能够为下拉列表正确设置回调,但我认为我的第二个回调无法正常工作.我了解如何创建动态下拉列表,但我不确定如何将其转换为实际绘制数据.

这就产生了这个情节.请注意,下拉列表是我想要的,但它没有绘制.如何添加权重"以制作所需的图?我所期望的只是一个简单的折线图,其中数据取决于所有选择的下拉菜单.

根据vestland 的建议,我包含了一个小得多的数据样本.这种情况下的具体值无关紧要,只是数据的结构.有关更简洁的数据,请参见上文.

解决方案

我一直无法弄清楚您的代码失败的原因.但我一直在整理一个我认为将接近您在此处寻找的示例.它建立在

用于选择的 Dash 应用程序 <代码>DF:区域 |作物:大豆 |列:total_precip_area

完整代码:

from jupyter_dash import JupyterDash将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html从 dash.dependencies 导入输入,输出# 数据从 jupyter_dash 导入 JupyterDash将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html从 dash.dependencies 导入输入、输出、状态、ClientsideFunction将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html将熊猫导入为 pd导入 plotly.graph_objs as go从 dash.dependencies 导入输入,输出将 dash_bootstrap_components 导入为 dbc将 numpy 导入为 np从 plotly.subplots 导入 make_subplots导入 plotly.express 作为 px将熊猫导入为 pd从熊猫进口时间戳将 numpy 导入为 np# 数据 ##########################################################################index1= [1,2,3,4]column1 =['time', '2m_temp_prod', 'total_precip_prod']index2= [1,2,3,4]columns2 = ['时间','2m_temp_area','total_precip_area']df_vals_prod = {'corn': pd.DataFrame(index=index1, columns = columns1,数据= np.random.randn(len(index1),len(columns1))).cumsum(),'大豆' : pd.DataFrame(index=index1, columns = columns1,数据= np.random.randn(len(index1),len(columns1))).cumsum()}df_vals_area= {'corn': pd.DataFrame(index=index2, columns = columns2,数据= np.random.randn(len(index2),len(columns2))).cumsum(),'大豆' : pd.DataFrame(index=index2, columns = columns2,数据= np.random.randn(len(index2),len(columns2))).cumsum()}# 模拟真实世界数据的数据属性df_vals_prod['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_prod['corn'].set_index('time', inplace = True)df_vals_prod['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_prod['soybeans'].set_index('time', inplace = True)df_vals_area['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_area['corn'].set_index('time', inplace = True)df_vals_area['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_area['soybeans'].set_index('time', inplace = True)# 破折号#######################################################################app = JupyterDash(__name__)# 权重all_options = {'产品':列表(df_vals_prod[列表(df_vals_prod.keys())[0]].columns),'区域':列表(df_vals_area[list(df_vals_prod.keys())[0]].columns)}app.layout = html.Div([dcc.RadioItems(id='生产无线电',options=[{'label': k, 'value': k} for k in all_options.keys()],价值='产品'),html.hr(),dcc.RadioItems(id='作物无线电',options=[{'label': k, 'value': k} for k in list(df_vals_prod.keys())],值=列表(df_vals_prod.keys())[0]),html.hr(),dcc.RadioItems(id='columns-radio'),html.hr(),html.Div(id='display-selected-values'),dcc.Graph(id="crop-graph")])#回调################################################################### 权重选择.@app.callback( # Dataframe PROD 或 AREA输出('列无线电','选项'),# 布局元素:dcc.RadioItems(id='produce-radio'...)[输入('生产收音机','值')])def set_columns_options(selected_produce):varz = [{'label': i, 'value': i} for i in all_options[selected_produce]]打印('cb1 输出:')打印(varz)返回 [{'label': i, 'value': i} for i in all_options[selected_produce]]# 列选择@app.callback(输出('列无线电','值'),# 布局元素:dcc.RadioItems(id='columns-radio'...)[输入('列无线电','选项')])def set_columns(available_options):返回 available_options[0]['value']# 裁剪选择@app.callback(输出('作物收音机','值'),# 布局元素:dcc.RadioItems(id='columns-radio'...)[输入('裁剪收音机','选项')])def set_crops(available_crops):返回 available_crops[0]['value']# 在自己的 div 中显示选择@app.callback( # 列 2m_temp_prod, 或者....输出('显示选择的值','孩子'),[输入('生产无线电','价值'),输入('作物收音机','值'),输入('列无线电','值')])def set_display_children(selected_produce, available_crops, selected_column):返回('DF:' + selected_produce +' | 作物:' + available_crops + ' | 列:'+ selected_column)# 根据选择制作图形@app.callback( # 列 2m_temp_prod, 或者....输出('裁剪图','图'),[输入('生产无线电','价值'),输入('作物收音机','值'),输入('列无线电','值')])def make_graph(selected_produce, available_crops, selected_column):# 数据源/权重如果 selected_produce == 'prod':dfd = df_vals_prod如果 selected_produce == 'area':dfd = df_vals_area# 情节图fig = go.Figure()fig.add_trace(go.Scatter(x=dfd[available_crops].index,y=dfd[available_crops][selected_column]))fig.update_layout(title=dict(text='DF:' + selected_produce +' | 作物:' + available_crops + ' | 列:'+ selected_column))返回(图)app.run_server(mode='inline', port = 8077, dev_tools_ui=True,dev_tools_hot_reload =真,线程=真)

编辑 1 - 下拉菜单.

要获得所需的下拉按钮,您只需更改每个按钮

dcc.RadioItems()

 dcc.Dropdown()

现在你会得到:

完整代码:

from jupyter_dash import JupyterDash将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html从 dash.dependencies 导入输入,输出# 数据从 jupyter_dash 导入 JupyterDash将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html从 dash.dependencies 导入输入、输出、状态、ClientsideFunction将 dash_core_components 导入为 dcc将 dash_html_components 导入为 html将熊猫导入为 pd导入 plotly.graph_objs as go从 dash.dependencies 导入输入,输出将 dash_bootstrap_components 导入为 dbc将 numpy 导入为 np从 plotly.subplots 导入 make_subplots导入 plotly.express 作为 px将熊猫导入为 pd从熊猫进口时间戳将 numpy 导入为 np# 数据 ##########################################################################index1= [1,2,3,4]column1 =['time', '2m_temp_prod', 'total_precip_prod']index2= [1,2,3,4]columns2 = ['时间','2m_temp_area','total_precip_area']df_vals_prod = {'corn': pd.DataFrame(index=index1, columns = columns1,数据= np.random.randn(len(index1),len(columns1))).cumsum(),'大豆' : pd.DataFrame(index=index1, columns = columns1,数据= np.random.randn(len(index1),len(columns1))).cumsum()}df_vals_area= {'corn': pd.DataFrame(index=index2, columns = columns2,数据= np.random.randn(len(index2),len(columns2))).cumsum(),'大豆' : pd.DataFrame(index=index2, columns = columns2,数据= np.random.randn(len(index2),len(columns2))).cumsum()}# 模拟真实世界数据的数据属性df_vals_prod['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_prod['corn'].set_index('time', inplace = True)df_vals_prod['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_prod['soybeans'].set_index('time', inplace = True)df_vals_area['corn']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_area['corn'].set_index('time', inplace = True)df_vals_area['soybeans']['time'] = [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),时间戳('2020-09-23 18:00:00'),时间戳('2020-09-24 00:00:00')]df_vals_area['soybeans'].set_index('time', inplace = True)# 破折号#######################################################################app = JupyterDash(__name__)# 权重all_options = {'产品':列表(df_vals_prod[列表(df_vals_prod.keys())[0]].columns),'区域':列表(df_vals_area[list(df_vals_prod.keys())[0]].columns)}app.layout = html.Div([dcc.Dropdown(id='生产无线电',options=[{'label': k, 'value': k} for k in all_options.keys()],值='区域'),# dcc.Dropdown(# id='生产无线电',# 选项=[# {'label': k, 'value': k} for k in all_options.keys()#],# 值='产品',#可清除=假),html.hr(),dcc.Dropdown(id='作物无线电',options=[{'label': k, 'value': k} for k in list(df_vals_prod.keys())],值=列表(df_vals_prod.keys())[0]),html.hr(),dcc.Dropdown(id='columns-radio'),html.hr(),html.Div(id='display-selected-values'),dcc.Graph(id="crop-graph")])# 回调################################################################### 权重选择.@app.callback( # Dataframe PROD 或 AREA输出('列无线电','选项'),# 布局元素:dcc.RadioItems(id='produce-radio'...)[输入('生产收音机','值')])def set_columns_options(selected_produce):varz = [{'label': i, 'value': i} for i in all_options[selected_produce]]打印('cb1 输出:')打印(varz)返回 [{'label': i, 'value': i} for i in all_options[selected_produce]]# 列选择@app.callback(输出('列无线电','值'),# 布局元素:dcc.RadioItems(id='columns-radio'...)[输入('列无线电','选项')])def set_columns(available_options):返回 available_options[0]['value']# 裁剪选择@app.callback(输出('作物收音机','值'),# 布局元素:dcc.RadioItems(id='columns-radio'...)[输入('裁剪收音机','选项')])def set_crops(available_crops):返回 available_crops[0]['value']# 在自己的 div 中显示选择@app.callback( # 列 2m_temp_prod, 或者....输出('显示选择的值','孩子'),[输入('生产无线电','价值'),输入('作物收音机','值'),输入('列无线电','值')])def set_display_children(selected_produce, available_crops, selected_column):返回('DF:' + selected_produce +' | 作物:' + available_crops + ' | 列:'+ selected_column)# 根据选择制作图形@app.callback( # 列 2m_temp_prod, 或者....输出('裁剪图','图'),[输入('生产无线电','价值'),输入('作物收音机','值'),输入('列无线电','值')])def make_graph(selected_produce, available_crops, selected_column):# 数据源/权重如果 selected_produce == 'prod':dfd = df_vals_prod如果 selected_produce == 'area':dfd = df_vals_area# 情节图fig = go.Figure()fig.add_trace(go.Scatter(x=dfd[available_crops].index,y=dfd[available_crops][selected_column]))fig.update_layout(title=dict(text='DF:' + selected_produce +' | 作物:' + available_crops + ' | 列:'+ selected_column))返回(图)app.run_server(mode='inline', port = 8077, dev_tools_ui=True,dev_tools_hot_reload =真,线程=真)

I am trying to create a Dash dashboard where dropdown options in one box are dependent on the previous dropdown selection.

The data consists of two dictionaries, with two keys each. Each key contains a dataframe with a couple of columns. The exact data:

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
import pandas as pd
from pandas import Timestamp
import numpy as np

df_vals_prod={'corn':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),
  2: Timestamp('2020-09-23 12:00:00'),
  3: Timestamp('2020-09-23 18:00:00'),
  4: Timestamp('2020-09-24 00:00:00')},
 '2m_temp_prod': {1: 0.020584322444347606,
  2: 0.08973907730395358,
  3: 2.3866310395722463,
  4: 3.065472457668321},
 'total_precip_prod': {1: 1.372708470272411,
  2: 2.135683294556938,
  3: 1.9811172016307312,
  4: 2.1082116841869323}}),
'soybeans':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),
  2: Timestamp('2020-09-23 12:00:00'),
  3: Timestamp('2020-09-23 18:00:00'),
  4: Timestamp('2020-09-24 00:00:00')},
 '2m_temp_prod': {1: 0.6989001827317545,
  2: -0.8699121426411993,
  3: -0.9484359259520706,
  4: 0.7391299158393124},
 'total_precip_prod': {1: -0.07639291299336869,
  2: 0.19182892415959496,
  3: 0.8719339093510236,
  4: 0.90586956349059}})}

df_vals_area={'corn':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),
  2: Timestamp('2020-09-23 12:00:00'),
  3: Timestamp('2020-09-23 18:00:00'),
  4: Timestamp('2020-09-24 00:00:00')},
 '2m_temp_area': {1: -1.6820417878457192,
  2: -0.2856437053872421,
  3: 0.3864022581278122,
  4: 0.5873739667356371},
 'total_precip_area': {1: 1.3703311242708185,
  2: 0.25528434511264525,
  3: 0.5007488191835624,
  4: -0.16292114222272375}}),
'soybeans':pd.DataFrame({'time': {1: Timestamp('2020-09-23 06:00:00'),
  2: Timestamp('2020-09-23 12:00:00'),
  3: Timestamp('2020-09-23 18:00:00'),
  4: Timestamp('2020-09-24 00:00:00')},
 '2m_temp_area': {1: 1.3789989862086967,
  2: -0.7797086923820608,
  3: 1.0695635889750523,
  4: 1.136561500804678},
 'total_precip_area': {1: -0.6035111830104833,
  2: -0.18237330469451313,
  3: -0.7820158376898607,
  4: -0.6117188028872137}})}

app = JupyterDash(external_stylesheets=[dbc.themes.SLATE])
weight_opts=['Production','Area']

controls = dbc.Card(
    [    dbc.FormGroup(
            [
                dbc.Label("Crop"),
                dcc.Dropdown(
                    id="Crop",
                    options=[
                        {"label": col, "value": col} for col in list(df_vals_prod.keys())
                    ],
                    value=list(df_vals_prod.keys())[0],
                    clearable=False,
                ),
            ]
        ),    
        
        
        
        dbc.FormGroup(
            [
                dbc.Label("Weighting"),
                dcc.Dropdown(
                    id="weights",
                    options=[
                        {"label": i, "value": i} for i in weight_opts
                    ],
                    value=weight_opts[0],
                    clearable=False,
                ),
            ]
        ),
        dbc.FormGroup(
            [
                dbc.Label("Forecast Variable"),
                dcc.Dropdown(
                    id="forecast_v",
                ),
            ]
        ),

    ],
    body=True,
)

app.layout = dbc.Container(
    [
        html.Hr(),
        dbc.Row([
            dbc.Col([
                dbc.Row([
                    dbc.Col(controls)
                ],  align="start"), 
                dbc.Row([
                    dbc.Col([
                        html.Br(),
                        dbc.Row([
                            dbc.Col([html.Div(id = 'txt1')
                            ])
                        ]),
                        html.Br(),
                        dbc.Row([
                            dbc.Col([html.Div(id = 'txt2')])
                        ])
                    ])
                ])
            ],xs = 2)
            ,
            dbc.Col([
                dbc.Row([
                    dbc.Col([html.Div(id = 'plot_title')],)
                ]),
                dbc.Row([
                    dbc.Col(dcc.Graph(id="crop-graph")),
                    #dbc.Col(dcc.Graph(id="cluster-graph"))
                ])
            ])
        ],), 
    ],
    fluid=True,
)

@app.callback(
    Output('forecast_v','options'),
    [Input('weights', 'value')]
)

def update_var_dropdown(weight):
    if weight=='Production':
        return [{'label': i, 'value': i} for i in df_vals_prod['corn'].columns[1:]]
    elif weight=='Area':
        return [{'label': i, 'value': i} for i in df_vals_area['corn'].columns[1:]]


@app.callback(
    Output("crop-graph", "figure"),
    [   Input("Crop", "value"),
        Input("weights", "value"),
        Input("forecast_v", "value"),

    ],
)

def crop_graph(Crop, val, weight):

    # plotly figure setup
    fig = make_subplots(specs=[[{"secondary_y": True}]])
    
    if weight:
        fig.add_trace(go.Scatter(name=val, x=df_vals_prod[Crop]['time'], y=((df_vals_prod[Crop][val]-273)*(9/5))+32, mode = 'lines', line=dict(color='red', width=4),
                                hovertemplate='Date: %{x|%d %b %H%M} UTC<br>Temp: %{y:.2f} F<extra></extra>'), secondary_y=False,
                  )
        fig.update_yaxes(title_text="<b>Temp (F)<b>", color='red', secondary_y=False,)
        fig.update_yaxes(title_text="<b>24hr Forecast Change (F)</b>", secondary_y=True)

    return(fig)
    
app.run_server(mode='external', port = 8099)

As you can see, this 6 hourly data and is meant to be plotted as a time series. Now I want to add a couple of dropdowns. The first dropdown (Crop) selects which crop to choose (corn or soybeans), which are the two keys from each dictionary.

The second dropdown (Weighting) now selects which dataframe we want to use. What the user selects in this second dropdown will determine the options to select in the third dropdown.

The third dropdown will select the actual variable (Forecast Variable), which is one of two columns available in each dataframe. So if in dropdown 2, "Production" is selected, the options for dropdown 3 would consist of '2m_temp_prod' or 'total_precip_prod'. For "Area" in dropdown 2, dropdown 3 options would be '2m_temp_area' or 'total_precip_area'.

Here is the code I have so far. I am able to setup the callback properly for the dropdowns, but I don't think my second callback is working properly. I understand how to create the dynamic dropdown, but I am not sure how to translate that to actually plotting the data.

That produces this plot. Notice that the dropdowns are what I want, but it doesn't plot. How do I add in the 'weight' to make the desired plot? What I would expect is just a simple line graph where the data depends on all of the dropdowns chosen.

Edit: as suggested by vestland, I am including a much smaller data sample. The specific values in this case don't matter, just the structure of the data. See above for more concise data.

解决方案

I haven't been able to figure out why your code fails. But I've been putting together an example that I think will come close to what you're looking for here. It builds on an example from the plotly docs, and so has a bit different layout from what you've got in your question. The main take-away is that three sets of radio buttons will let you:

  1. select a weight: ['prod', 'area'],
  2. which in turn will define the options in another callback: ['2m_temp_prod', 'total_precip_prod'] or ['2m_temp_area', 'total_precip_area'].
  3. And you're also able to select produce ['corn', 'soybeans']

It's very possible that I've misunderstood the logic of what you want to achieve here. But just give me some feedback along the way and we can work out the details.

Dash app for selection DF: prod | Crops: corn | Column: 2m_temp_prod

Dash app for selection DF: area | Crops: soybeans | Column: total_precip_area

Complete code:

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

# data
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
import pandas as pd
from pandas import Timestamp
import numpy as np

# data ##########################################################################
index1= [1,2,3,4]
columns1 =['time', '2m_temp_prod' , 'total_precip_prod']

index2= [1,2,3,4]
columns2 = ['time', '2m_temp_area', 'total_precip_area']

df_vals_prod = {'corn': pd.DataFrame(index=index1, columns = columns1,
                                data= np.random.randn(len(index1),len(columns1))).cumsum(),
                'soybeans' : pd.DataFrame(index=index1, columns = columns1,
                                     data= np.random.randn(len(index1),len(columns1))).cumsum()}

df_vals_area= {'corn': pd.DataFrame(index=index2, columns = columns2,
                                data= np.random.randn(len(index2),len(columns2))).cumsum(),
               'soybeans' : pd.DataFrame(index=index2, columns = columns2,
                                     data= np.random.randn(len(index2),len(columns2))).cumsum()}

# mimic data properties of your real world data
df_vals_prod['corn']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'), 
                                  Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['corn'].set_index('time', inplace = True)
df_vals_prod['soybeans']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
                                      Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['soybeans'].set_index('time', inplace = True)

df_vals_area['corn']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
                                  Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['corn'].set_index('time', inplace = True)
df_vals_area['soybeans']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
                                      Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['soybeans'].set_index('time', inplace = True)

# dash ##########################################################################
app = JupyterDash(__name__)

# weighting
all_options = {
    'prod': list(df_vals_prod[list(df_vals_prod.keys())[0]].columns),
    'area': list(df_vals_area[list(df_vals_prod.keys())[0]].columns)
}

app.layout = html.Div([
    dcc.RadioItems(
        id='produce-radio',
        options=[{'label': k, 'value': k} for k in all_options.keys()],
        value='prod'
    ),

    html.Hr(),
    
    dcc.RadioItems(
        id='crop-radio',
        options=[{'label': k, 'value': k} for k in list(df_vals_prod.keys())],
        value=list(df_vals_prod.keys())[0]
    ),

    html.Hr(),

    dcc.RadioItems(id='columns-radio'),

    html.Hr(),

    html.Div(id='display-selected-values'),
    
    dcc.Graph(id="crop-graph")
])

# Callbacks #####################################################################

# Weighting selection.
@app.callback( # Dataframe PROD or AREA
    Output('columns-radio', 'options'),
    # layout element: dcc.RadioItems(id='produce-radio'...)
    [Input('produce-radio', 'value')])
def set_columns_options(selected_produce):
    varz =  [{'label': i, 'value': i} for i in all_options[selected_produce]]
    print('cb1 output: ')
    print(varz)
    return [{'label': i, 'value': i} for i in all_options[selected_produce]]

# Columns selection
@app.callback( 
    Output('columns-radio', 'value'),
    # layout element: dcc.RadioItems(id='columns-radio'...)
    [Input('columns-radio', 'options')])
def set_columns(available_options):
    return available_options[0]['value']

# Crop selection
@app.callback( 
    Output('crop-radio', 'value'),
    # layout element: dcc.RadioItems(id='columns-radio'...)
    [Input('crop-radio', 'options')])
def set_crops(available_crops):
    return available_crops[0]['value']

# Display selections in its own div
@app.callback( # Columns 2m_temp_prod, or....
    Output('display-selected-values', 'children'),
    [Input('produce-radio', 'value'),
     Input('crop-radio', 'value'),
     Input('columns-radio', 'value')])
def set_display_children(selected_produce, available_crops, selected_column):
    return('DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column)

# Make a figure based on the selections
@app.callback( # Columns 2m_temp_prod, or....
    Output('crop-graph', 'figure'),
    [Input('produce-radio', 'value'),
     Input('crop-radio', 'value'),
     Input('columns-radio', 'value')])
def make_graph(selected_produce, available_crops, selected_column):
    
    # data source / weighting
    if selected_produce == 'prod':
        dfd = df_vals_prod
    if selected_produce == 'area':
        dfd = df_vals_area
    
    # plotly figure
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=dfd[available_crops].index, y=dfd[available_crops][selected_column]))
    fig.update_layout(title=dict(text='DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column))
    return(fig)

app.run_server(mode='inline', port = 8077, dev_tools_ui=True,
          dev_tools_hot_reload =True, threaded=True)

Edit 1 - Dropdown menus.

All you have to do to get the desired dropdown buttons is to change each

dcc.RadioItems()

to

 dcc.Dropdown()

Now you'll get:

Complete code:

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

# data
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
import pandas as pd
from pandas import Timestamp
import numpy as np

# data ##########################################################################
index1= [1,2,3,4]
columns1 =['time', '2m_temp_prod' , 'total_precip_prod']

index2= [1,2,3,4]
columns2 = ['time', '2m_temp_area', 'total_precip_area']

df_vals_prod = {'corn': pd.DataFrame(index=index1, columns = columns1,
                                data= np.random.randn(len(index1),len(columns1))).cumsum(),
                'soybeans' : pd.DataFrame(index=index1, columns = columns1,
                                     data= np.random.randn(len(index1),len(columns1))).cumsum()}

df_vals_area= {'corn': pd.DataFrame(index=index2, columns = columns2,
                                data= np.random.randn(len(index2),len(columns2))).cumsum(),
               'soybeans' : pd.DataFrame(index=index2, columns = columns2,
                                     data= np.random.randn(len(index2),len(columns2))).cumsum()}

# mimic data properties of your real world data
df_vals_prod['corn']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'), 
                                  Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['corn'].set_index('time', inplace = True)
df_vals_prod['soybeans']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
                                      Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_prod['soybeans'].set_index('time', inplace = True)

df_vals_area['corn']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
                                  Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['corn'].set_index('time', inplace = True)
df_vals_area['soybeans']['time'] =   [Timestamp('2020-09-23 06:00:00'), Timestamp('2020-09-23 12:00:00'),
                                      Timestamp('2020-09-23 18:00:00'), Timestamp('2020-09-24 00:00:00')]
df_vals_area['soybeans'].set_index('time', inplace = True)

# dash ##########################################################################
app = JupyterDash(__name__)

# weighting
all_options = {
    'prod': list(df_vals_prod[list(df_vals_prod.keys())[0]].columns),
    'area': list(df_vals_area[list(df_vals_prod.keys())[0]].columns)
}

app.layout = html.Div([
    dcc.Dropdown(
        id='produce-radio',
        options=[{'label': k, 'value': k} for k in all_options.keys()],
        value='area'
    ),
#     dcc.Dropdown(
#     id='produce-radio',
#     options=[
#         {'label': k, 'value': k} for k in all_options.keys()
#     ],
#     value='prod',
#     clearable=False),
    

    html.Hr(),
    
    dcc.Dropdown(
        id='crop-radio',
        options=[{'label': k, 'value': k} for k in list(df_vals_prod.keys())],
        value=list(df_vals_prod.keys())[0]
    ),

    html.Hr(),

    dcc.Dropdown(id='columns-radio'),

    html.Hr(),

    html.Div(id='display-selected-values'),
    
    dcc.Graph(id="crop-graph")
])

# Callbacks #####################################################################

# Weighting selection.
@app.callback( # Dataframe PROD or AREA
    Output('columns-radio', 'options'),
    # layout element: dcc.RadioItems(id='produce-radio'...)
    [Input('produce-radio', 'value')])
def set_columns_options(selected_produce):
    varz =  [{'label': i, 'value': i} for i in all_options[selected_produce]]
    print('cb1 output: ')
    print(varz)
    return [{'label': i, 'value': i} for i in all_options[selected_produce]]

# Columns selection
@app.callback( 
    Output('columns-radio', 'value'),
    # layout element: dcc.RadioItems(id='columns-radio'...)
    [Input('columns-radio', 'options')])
def set_columns(available_options):
    return available_options[0]['value']

# Crop selection
@app.callback( 
    Output('crop-radio', 'value'),
    # layout element: dcc.RadioItems(id='columns-radio'...)
    [Input('crop-radio', 'options')])
def set_crops(available_crops):
    return available_crops[0]['value']

# Display selections in its own div
@app.callback( # Columns 2m_temp_prod, or....
    Output('display-selected-values', 'children'),
    [Input('produce-radio', 'value'),
     Input('crop-radio', 'value'),
     Input('columns-radio', 'value')])
def set_display_children(selected_produce, available_crops, selected_column):
    return('DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column)

# Make a figure based on the selections
@app.callback( # Columns 2m_temp_prod, or....
    Output('crop-graph', 'figure'),
    [Input('produce-radio', 'value'),
     Input('crop-radio', 'value'),
     Input('columns-radio', 'value')])
def make_graph(selected_produce, available_crops, selected_column):
    
    # data source / weighting
    if selected_produce == 'prod':
        dfd = df_vals_prod
    if selected_produce == 'area':
        dfd = df_vals_area
    
    # plotly figure
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=dfd[available_crops].index, y=dfd[available_crops][selected_column]))
    fig.update_layout(title=dict(text='DF: ' + selected_produce +' | Crops: ' + available_crops + ' | Column: '+ selected_column))
    return(fig)

app.run_server(mode='inline', port = 8077, dev_tools_ui=True,
          dev_tools_hot_reload =True, threaded=True)

这篇关于为动态下拉列表正确设置回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆