Я хочу создать простое приложение для черточки, в котором на входе указан символ акции, а на выходе - его цена за определенный период времени.Тем не менее, я хочу дать пользователю 2 способа выбора ввода: либо наберите его в текстовом поле, либо выберите из выпадающего списка некоторые общие акции.
Это мой код, чтобы сделать это:
import pandas_datareader.data as web
import datetime
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = dash.Dash()
app.layout = html.Div(children=[
html.Div(children='Symbol to graph:'),
dcc.Input(id='input', value='', type='text'),
html.Div(children='Frequent options:'),
dcc.Dropdown(
options=[
{'label': 'Apple (AAPL)', 'value': 'AAPL'},
{'label': 'Microsoft (MSFT)', 'value': 'MSFT'},
{'label': 'Amazon (AMZN)', 'value': 'AMZN'},
{'label': 'Tesla (TSLA)', 'value': 'TSLA'}
],
style={'width': '40%'},
id='freq-inputs'
),
html.Div(id='output-graph'),
html.Div(id='freq-input-graph'),
])
@app.callback(
Output(component_id='output-graph', component_property='children'),
[Input(component_id='input', component_property='value')]
)
def update_value(input_data):
start = datetime.datetime(2015, 1, 1)
end = datetime.datetime.now()
df = web.DataReader(input_data, 'iex', start, end)
df.reset_index(inplace=True)
df.set_index("date", inplace=True)
return dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': df.index, 'y': df.close, 'type': 'line', 'name': input_data},
],
'layout': {
'title': input_data
}
}
)
@app.callback(
Output(component_id='output-graph', component_property='children'),
[Input(component_id='freq-inputs', component_property='value')]
)
def update_value(input_data):
start = datetime.datetime(2015, 1, 1)
end = datetime.datetime(2018, 9, 24) #datetime.datetime.now()
df = web.DataReader(input_data, 'iex', start, end)
df.reset_index(inplace=True)
df.set_index("date", inplace=True)
return dcc.Graph(
id='example-graph',
figure={
'data': [
{'x': df.index, 'y': df.close, 'type': 'line', 'name': input_data},
],
'layout': {
'title': input_data
}
}
)
if __name__ == '__main__':
app.run_server(debug=True)
Как видите, мне пришлось написать 2 деления для каждого типа ввода (html.Div(id='output-graph')
и html.Div(id='freq-input-graph')
) и, следовательно, 2 функции-оболочки обратного вызова, которые идентичны, за исключением идентификаторов компонентов ввода и вывода.Это потому, что когда я пытался использовать тот же компонент div для вывода, я получал сообщение об ошибке:
You have already assigned a callback to the output
with ID "output-graph" and property "children". An output can only have
a single callback function. Try combining your inputs and
callback functions together into one function.
Помимо избыточного кода, есть еще одна проблема, с которой я сталкиваюсь в этом коде.Если я наберу символ акции, он построит график;если я затем выберу опцию из выпадающего списка, последний график будет отображен на том же элементе div, что и предыдущий, поэтому мы можем видеть только один график в любой момент времени.Однако, если я сначала выберу опцию из выпадающего списка, а затем напечатал символ, он строит 2 разных графика.
Это потому, что html.Div(id='output-graph')
объявлено / определено выше html.Div(id='freq-input-graph')
в определении макета приложения,Если я поменяю порядок, будет замечено противоположное поведение.
Как мне это исправить?