python - 我的简单 Dash 应用程序有什么问题导致我的绘图无法正常工作?
问题描述
我制作了一个 Dash 应用程序,它从我的 SQL 数据库中绘制股票市场数据。该应用程序使用一个可以有多个值的输入。就我而言,此输入仅指股票。因此,用户可以在一个输入中链接多个股票,以创建一个带有它们的价格的图,相互叠加。使用 Flask @callback 方法,我可以做到这一点。
图表不工作,输入栏效果很好,用户可以选择多只股票。当然,它与正在传递的数据有关,但我找不到在哪里,而且我似乎修复得越多,它就越坏......
在下面查看我的代码:
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
import plotly.graph_objects as go
import dash_html_components as html
from dash.exceptions import PreventUpdate
#PostgreSQL Connection
from connect import *
# CSS
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
# Pre-load:
stock_ids = execute_query(conn, "SELECT DISTINCT id FROM security_price;")
stock_ids = [i[0] for i in stock_ids]
options = [{'label': i, 'value': i} for i in stock_ids]
# Create Dash app
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Create app layout
app.layout = html.Div(
[ html.Div(className='row', # Define the row element
children=[
# left element
html.Div(className='eight columns div-user-controls',
children = [
html.H2('SP500 Equity Analyzer'),
html.P(''' Compare stocks on your watchlist.'''),
dcc.Dropdown(id="my-multi-dynamic-dropdown", options=options, multi=True, placeholder="Select a Symbol"),
dcc.Graph(id='timeseries', config={'displayModeBar': False}),
]
),
# right element
html.Div(className='four columns div-for-charts bg-grey'),
]),
])
# User callbacks
#user input
@app.callback(
dash.dependencies.Output("my-multi-dynamic-dropdown", "options"),
[dash.dependencies.Input("my-multi-dynamic-dropdown", "search_value")],
[dash.dependencies.State("my-multi-dynamic-dropdown", "value")],
)
def update_multi_options(search_value, value):
if not search_value:
raise PreventUpdate
else:
return [
o for o in options if search_value in o["label"] or o["value"] in (value or [])
]
# timeseries graph
@app.callback(Output('timeseries', 'figure'),
[Input("my-multi-dynamic-dropdown", 'search_value')],
[State("my-multi-dynamic-dropdown", "value")],
)
def update_timeseries(input_data, state):
if input_data == None:
raise PreventUpdate
if state == None:
raise PreventUpdate
# Draw and append traces for each stock
trace = []
for stock in input_data:
stock_info = execute_query(conn, f"SELECT date, close FROM security_price WHERE security_price.id = '{stock}' ;")
for row in stock_info:
date = []
adj_close = []
date.append(row[0])
adj_close.append(row[1])
# STEP 2
trace.append(go.Scatter(x=date,
y=adj_close,
mode='lines',
opacity=0.7,
name=stock,
textposition='bottom center'))
# STEP 3
traces = [trace]
data = [val for sublist in traces for val in sublist]
# Define Figure
# STEP 4
figure = {'data': traces,
'layout': go.Layout(
colorway=["#5E0DAC", '#FF4F00', '#375CB1', '#FF7400', '#FFF400', '#FF0056'],
template='plotly_dark',
paper_bgcolor='rgba(0, 0, 0, 0)',
plot_bgcolor='rgba(0, 0, 0, 0)',
margin={'b': 15},
hovermode='x',
autosize=True,
title={'text': 'Stock Prices', 'font': {'color': 'white'}, 'x': 0.5},
),
}
return figure
if __name__ == '__main__':
app.run_server(debug=True)
这是我得到的错误:
Invalid argument `figure.data[0]` passed into Graph with ID "timeseries".
Expected `object`.
Was supplied type `array`.
除了 Dash 的这个 Javascript 错误:
Error: Invalid argument `figure.data[0]` passed into Graph with ID "timeseries".
Expected `object`.
Was supplied type `array`.
at propTypeErrorHandler (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/dash_renderer.v1_8_0m1599348644.dev.js:90547:9)
at CheckedComponent (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/dash_renderer.v1_8_0m1599348644.dev.js:84930:77)
at renderWithHooks (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:14960:20)
at updateFunctionComponent (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:17193:22)
at beginWork (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:18778:18)
at HTMLUnknownElement.callCallback (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:182:16)
at Object.invokeGuardedCallbackDev (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:231:18)
at invokeGuardedCallback (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:286:33)
at beginWork$1 (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:23369:9)
at performUnitOfWork (http://127.0.0.1:8050/_dash-component-suites/dash_renderer/react-dom@16.v1_8_0m1599348644.13.0.js:22323:14)
非常感谢我的程序出错的地方。
解决方案
这就是您的问题的来源:
# Draw and append traces for each stock
trace = []
for stock in input_data:
stock_info = execute_query(conn, f"SELECT date, close FROM security_price WHERE security_price.id = '{stock}' ;")
for row in stock_info:
date = []
adj_close = []
date.append(row[0])
adj_close.append(row[1])
# STEP 2
trace.append(go.Scatter(x=date,
y=adj_close,
mode='lines',
opacity=0.7,
name=stock,
textposition='bottom center'))
# STEP 3
traces = [trace]
您已经制作trace
了一个列表,然后将其放入traces
另一个列表中。您应该将所有go.Scatter
对象放入traces
中,以便列表包含Scatter
对象,而不是子列表。