正确设置动态下拉列表的回调 plotly dash
Properly setting up callbacks for dynamic dropdowns plotly dash
我正在尝试创建一个 Dash 仪表板,其中一个框中的下拉选项取决于前一个下拉列表 selection。
数据由两个字典组成,每个字典有两个键。每个键都包含一个带有几列的数据框。具体数据:
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)
如您所见,这 6 小时的数据旨在绘制为时间序列。现在我想添加几个下拉菜单。第一个下拉列表 (Crop) select 选择哪个作物(玉米或大豆),这是每个字典中的两个键。
第二个下拉菜单(加权)现在 select我们要使用哪个数据框。第二个下拉列表中的用户 select 将决定第三个下拉列表中 select 的选项。
第三个下拉列表将 select 实际变量(预测变量),它是每个数据框中可用的两列之一。因此,如果在下拉列表 2 中,“Production”是 selected,则下拉列表 3 的选项将包含“2m_temp_prod”或 'total_precip_prod'。对于下拉菜单 2 中的“区域”,下拉菜单 3 选项将为“2m_temp_area”或'total_precip_area'。
这是我目前的代码。我能够为下拉菜单正确设置回调,但我认为我的第二个回调无法正常工作。我了解如何创建动态下拉列表,但我不确定如何将其转化为实际绘制数据。
产生了这个情节。请注意,下拉菜单是我想要的,但它没有绘制。如何添加 'weight' 来制作所需的情节?我期望的只是一个简单的折线图,其中的数据取决于所有选择的下拉菜单。
编辑:根据 vestland 的建议,我包含了一个小得多的数据样本。这种情况下的具体值并不重要,重要的是数据的结构。请参阅上文以获取更简洁的数据。
我无法弄清楚您的代码失败的原因。但我一直在整理一个示例,我 认为 将接近您在这里寻找的内容。它建立在 example from the plotly docs 之上,因此布局与您在问题中得到的布局略有不同。主要的take-away是三组单选按钮可以让你:
- select一个权重:
['prod', 'area']
,
- 这又将在另一个回调中定义选项:
['2m_temp_prod', 'total_precip_prod']
或 ['2m_temp_area', 'total_precip_area']
.
- 而且您还可以 select 生成
['corn', 'soybeans']
很可能我误解了你想在这里实现的逻辑。但只要在过程中给我一些反馈,我们就可以制定出细节。
selection DF: prod | Crops: corn | Column: 2m_temp_prod
的 Dash 应用程序
selection DF: area | Crops: soybeans | Column: total_precip_area
的 Dash 应用程序
完整代码:
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)
编辑 1 - 下拉菜单。
要获得所需的下拉按钮,您只需更改每个按钮
dcc.RadioItems()
至
dcc.Dropdown()
现在您将获得:
完整代码:
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)
我正在尝试创建一个 Dash 仪表板,其中一个框中的下拉选项取决于前一个下拉列表 selection。
数据由两个字典组成,每个字典有两个键。每个键都包含一个带有几列的数据框。具体数据:
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)
如您所见,这 6 小时的数据旨在绘制为时间序列。现在我想添加几个下拉菜单。第一个下拉列表 (Crop) select 选择哪个作物(玉米或大豆),这是每个字典中的两个键。
第二个下拉菜单(加权)现在 select我们要使用哪个数据框。第二个下拉列表中的用户 select 将决定第三个下拉列表中 select 的选项。
第三个下拉列表将 select 实际变量(预测变量),它是每个数据框中可用的两列之一。因此,如果在下拉列表 2 中,“Production”是 selected,则下拉列表 3 的选项将包含“2m_temp_prod”或 'total_precip_prod'。对于下拉菜单 2 中的“区域”,下拉菜单 3 选项将为“2m_temp_area”或'total_precip_area'。
这是我目前的代码。我能够为下拉菜单正确设置回调,但我认为我的第二个回调无法正常工作。我了解如何创建动态下拉列表,但我不确定如何将其转化为实际绘制数据。
产生了这个情节。请注意,下拉菜单是我想要的,但它没有绘制。如何添加 'weight' 来制作所需的情节?我期望的只是一个简单的折线图,其中的数据取决于所有选择的下拉菜单。
编辑:根据 vestland 的建议,我包含了一个小得多的数据样本。这种情况下的具体值并不重要,重要的是数据的结构。请参阅上文以获取更简洁的数据。
我无法弄清楚您的代码失败的原因。但我一直在整理一个示例,我 认为 将接近您在这里寻找的内容。它建立在 example from the plotly docs 之上,因此布局与您在问题中得到的布局略有不同。主要的take-away是三组单选按钮可以让你:
- select一个权重:
['prod', 'area']
, - 这又将在另一个回调中定义选项:
['2m_temp_prod', 'total_precip_prod']
或['2m_temp_area', 'total_precip_area']
. - 而且您还可以 select 生成
['corn', 'soybeans']
很可能我误解了你想在这里实现的逻辑。但只要在过程中给我一些反馈,我们就可以制定出细节。
selection DF: prod | Crops: corn | Column: 2m_temp_prod
的 Dash 应用程序
selection DF: area | Crops: soybeans | Column: total_precip_area
的 Dash 应用程序
完整代码:
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)
编辑 1 - 下拉菜单。
要获得所需的下拉按钮,您只需更改每个按钮
dcc.RadioItems()
至
dcc.Dropdown()
现在您将获得:
完整代码:
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)