Dash Python how to make multiple updating graphs, how to title - python

new coder here, I'm trying to make 4 graphs that share the same random data (although I plan on splitting them apart later). When it was just the one graph it took the random data fine and automatically scaled. In the go.layout there's no way to put which graph you're labeling. Now that I've added multiple none of them have any titles, axis labels, or data. Please help!
import dash
from dash.dependencies import Output, Input
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import random
import plotly.graph_objs as go
from collections import deque
#setting first points
X = deque(maxlen = 20)
X.append(1)
Y = deque(maxlen = 20)
Y.append(1)
#app settings, html layout
app = dash.Dash(__name__)
app.layout = html.Div(children=[
html.H1([
html.H1(children='Graphs'),
dcc.Graph(id = 'Battery Voltage', animate = True),
dcc.Interval(
id = 'graph-update',
interval = 1000,
n_intervals = 0
),
],
),
html.Div(
[
dcc.Graph(id = 'Signal', animate = True),
dcc.Interval(
id = 'graph-update2',
interval = 1000,
n_intervals = 0
),
],
),
html.Div(
[
dcc.Graph(id = 'Health', animate = True),
dcc.Interval(
id = 'graph-update3',
interval = 1000,
n_intervals = 0
),
],
),
html.Div(
[
dcc.Graph(id = 'Prognastics', animate = True),
dcc.Interval(
id = 'graph-update4',
interval = 1000,
n_intervals = 0
),
],
)])
#this is what keeps the graph updating
#app.callback(
[Output('Battery Voltage', 'figure'),
Output('Signal', 'figure'),
Output('Health', 'figure'),
Output('Prognastics', 'figure')],
[ Input('graph-update', 'n_intervals'),
Input('graph-update2', 'n_intervals'),
Input('graph-update3', 'n_intervals'),
Input('graph-update4', 'n_intervals')]
)
def update_graph_scatter(n):
X.append(X[-1]+1)
Y.append(Y[-1]+Y[-1] * random.uniform(-0.1,0.1))
data = go.Scatter(
x=list(X),
y=list(Y),
name='Scatter',
mode= 'lines+markers'
)
return {'data': [data],
'layout' : go.Layout(title="Battery Voltage",
xaxis_title="Time",
yaxis_title="Voltage",
xaxis=dict(range=[min(X),max(X)]),
yaxis = dict(range = [min(Y),max(Y)])
)
}
if __name__ == '__main__':
app.run_server()
When ran with multiple
Just the one

if anyone else has this problem, the definition has to come immediately after their callback. My formatting was also bad I guess. It should look like:
#app.callback(Output('Health', 'figure'),
Input('graph-update3', 'n_intervals'))
def update_graph3(n):
X.append(X[-1]+1)
Y.append(Y[-1]+Y[-1] * random.uniform(-0.1,0.1))
#those are random points, we'd socket something in
data = go.Scatter(
x=list(X),
y=list(Y),
name='Scatter',
mode= 'lines+markers'
)
print("data:", data)
return {'data': [data],
'layout' : go.Layout(title="Health",
xaxis_title="Time",
yaxis_title="Health",
xaxis=dict(range=[min(X),max(X)]),
yaxis = dict(range = [min(Y),max(Y)])
)
}

Related

Combining a callback and a for loop to return multiple values

Using Dash, I have a callback whose function should return several values with a for loop like so:
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
df = pd.read_json(data)
nb_columns = len(df.columns)
for i in range(nb_columns):
return(update_graphs(data, df.columns[i+1], i, 100))
However, since I am using return inside a for loop, the process stops the loop after the first iteration. I am looking at using yield to create a generator. However, it does not fix my issue because I am working inside a callback and I need the values to be returned. I can't use print(next(...) instead of return.
Is there a way to return successively all the values inside the for loop? If not, what could be a way to approach this problem?
Here is a minimal working example App:
import dash
from dash.dependencies import Output, Input, State, MATCH, ALL
from dash import dcc, html, ctx
import plotly
import plotly.express as px
import random
import plotly.graph_objs as go
import pandas as pd
# Initializing the data with the correct format
init_store = {}
n=3
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int'), 'c':pd.Series(dtype='int'), 'd':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store['0'] = init_df
for i in range(n):
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store[f'{i+1}'] = init_df
# Function to update the dataframes with the new observations
def get_data(json_data):
df = pd.read_json(json_data)
compteur = df['a'][len(df['a'])-1]
if len(df.columns) > 2:
new_row = {'a':compteur + 1, 'b':random.randint(13,26), 'c':random.randint(13,26), 'd':random.randint(13,26)}
else:
new_row = {'a':compteur + 1, 'b':random.randint(13,26)}
df = df.shift(periods=-1)
df.iloc[len(df)-1] = new_row
return(df.to_json())
# Function to update the graphs based on the dataframes
def update_graphs(json_data, column, index, nb_obs_kept):
df = pd.read_json(json_data)
nb_obs = df.shape[0]
x_new = df['a'][len(df)-1]
y_new = df[column][nb_obs-1]
return dict(x=[[x_new]], y=[[y_new]]), index, nb_obs_kept
colors = px.colors.qualitative.G10
def generate_graph_containers(index, json_data):
dataframe = pd.read_json(json_data)
X = dataframe['a']
Y = dataframe.loc[:, dataframe.columns != 'a']
graph_id = {'type': 'graph-', 'index': index}
return(
html.Div(
html.Div(
dcc.Graph(
id=graph_id,
style={"height": "8rem"},
config={
"staticPlot": False,
"editable": False,
"displayModeBar": False,
},
figure=go.Figure(
{
"data": [
{
"x": list(X),
"y": list(Y[Y.columns[i]]),
"mode": "lines",
"name": Y.columns[i],
"line": {"color": colors[i+2]},
}
for i in range(len(Y.columns))
],
"layout": {
"uirevision": True,
"margin": dict(l=0, r=0, t=4, b=4, pad=0),
"xaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"yaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"paper_bgcolor": "rgba(0,0,0,0)",
"plot_bgcolor": "rgba(0,0,0,0)",
}
}
)
)
)
)
)
app = dash.Dash(__name__)
store = [dcc.Store(id={'type':'store-', 'index':i}, data=init_store[str(i)].to_json()) for i in range(n)]
def make_layout():
return(
html.Div(
[
html.Div(
store
),
dcc.Interval(
id = 'interval',
interval = 1000,
n_intervals = 0
),
html.Div(
[
generate_graph_containers(str(i), store[i].data) for i in range(n)
]
)
]
)
)
app.layout = make_layout
#app.callback(
Output(component_id={'type':'store-', 'index':MATCH}, component_property='data'),
[
Input('interval', 'n_intervals'),
State(component_id={'type':'store-', 'index':MATCH}, component_property='data')
]
)
def update_data(time, data):
return(get_data(data))
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graphs_callback(data):
df = pd.read_json(data)
nb_columns = len(df.columns)
for i in range(nb_columns):
return(update_graphs(data, df.columns[i+1], i, 100))
if __name__ == '__main__':
app.run_server(debug=True, host='0.0.0.0', port=8050)
Any help is appreciated!

Dash dynamic live graph update of multiple traces

I am trying to build a Dash app that takes several different data sources as inputs and plots one graph for each data source. As the data is a continuous stream, I store only a small amount (the last 50 observations) of data inside a dcc.Store, one for each data source.
I therefore have one callback allowing me to update the data contained inside the different dcc.Store using pattern matching callback.
I would also like to have one pattern matching callback allowing me to update the dcc.Graph associated with each of the data source, using the data in the dcc.Store.
However, some of the datasources give me several time series that I would like to plot all on the same graph using one trace for each time series. My update_graphs function seems to be working fine to update the graph with only one trace but not when there are multiple traces. I think I am not returning the proper format to update multiple traces with extendData property of the graph.
I want my app to be dynamic so I'm trying to avoid having one call back for each data source
Here is a small example:
import dash
from dash.dependencies import Output, Input, State, MATCH, ALL
from dash import dcc, html
import plotly
import random
import plotly.graph_objs as go
import pandas as pd
# Initializing the data with the correct format
init_store = {}
n=3
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int'), 'c':pd.Series(dtype='int'), 'd':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store['0'] = init_df
for i in range(n):
init_df = pd.DataFrame({'a':pd.Series(dtype='int'), 'b':pd.Series(dtype='int')}, index=range(50))
init_df['a'] = init_df.index
init_store[f'{i+1}'] = init_df
# Function to update the dataframes with the new observations
def get_data(json_data):
df = pd.read_json(json_data)
compteur = df['a'][len(df['a'])-1]
if len(df.columns) > 2:
new_row = {'a':compteur + 1, 'b':random.randint(13,26), 'c':random.randint(13,26), 'd':random.randint(13,26)}
else:
new_row = {'a':compteur + 1, 'b':random.randint(13,26)}
df = df.shift(periods=-1)
df.iloc[len(df)-1] = new_row
return(df.to_json())
# Function to update the graphs based on the dataframes
def update_graphs(json_data):
df = pd.read_json(json_data)
nb_obs = df.shape[0]
x_new = df['a'][len(df)-1]
if len(df.loc[:, df.columns != 'a'].columns) > 1:
df = df.loc[:, df.columns != 'a']
return_lists = []
for i in range(len(df.columns)):
return_lists.append([dict(x=[[x_new]], y=[[df[df.columns[i]][nb_obs-1]]]), [i]])
return return_lists
else:
y_new = df['b'][nb_obs-1]
return dict(x=[[x_new]], y=[[y_new]]), [0]
def generate_graph_containers(index, json_data):
dataframe = pd.read_json(json_data)
X = dataframe['a']
Y = dataframe.loc[:, dataframe.columns != 'a']
graph_id = {'type': 'graph-', 'index': index}
return(
html.Div(
html.Div(
dcc.Graph(
id=graph_id,
style={"height": "8rem"},
config={
"staticPlot": False,
"editable": False,
"displayModeBar": False,
},
figure=go.Figure(
{
"data": [
{
"x": list(X),
"y": list(Y[variable]),
"mode": "lines",
"name": variable,
"line": {"color": "#f4d44d"},
}
for variable in Y.columns
],
"layout": {
"uirevision": True,
"margin": dict(l=0, r=0, t=4, b=4, pad=0),
"xaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"yaxis": dict(
showline=False,
showgrid=False,
zeroline=False,
showticklabels=False,
),
"paper_bgcolor": "rgba(0,0,0,0)",
"plot_bgcolor": "rgba(0,0,0,0)",
}
}
)
)
)
)
)
app = dash.Dash(__name__)
store = [dcc.Store(id={'type':'store-', 'index':i}, data=init_store[str(i)].to_json()) for i in range(n)]
def make_layout():
return(
html.Div(
[
html.Div(
store
),
dcc.Interval(
id = 'interval',
interval = 1000,
n_intervals = 0
),
html.Div(
[
generate_graph_containers(str(i), store[i].data) for i in range(n)
]
)
]
)
)
app.layout = make_layout
#app.callback(
Output(component_id={'type':'store-', 'index':MATCH}, component_property='data'),
[
Input('interval', 'n_intervals'),
State(component_id={'type':'store-', 'index':MATCH}, component_property='data')
]
)
def update_data(time, data):
return(get_data(data))
#app.callback(
Output(component_id={'type':'graph-', 'index':MATCH}, component_property='extendData'),
Input(component_id={'type':'store-', 'index':MATCH}, component_property="data")
)
def update_graph(data):
print(pd.read_json(data))
return (
update_graphs(data)
)
if __name__ == '__main__':
app.run_server(debug=True)

Is it possible to use zoom from one graph in a Dash app to select input for second graph

I have a dash app that plots a dataframe which has a date component, and an entry that is either true or false. There are two graphs in the dashboard, one with the data vs date, and one with a percentage of True/False like below:
I can zoom in on the date range and select a subset clicking with the mouse.
I would like to feed this range back into the second graph.
At the moment to produce the above dashboard the relevant part of the code looks like:
from re import template
import pandas as pd
import plotly.express as px
from dash import Dash, Input, Output, dcc, html
from flask import globals
def init_dashboard(server):
evicted_df = pd.read_csv("app/data/evicted_jobs_node.csv", sep="\t")
all_df = pd.read_csv("app/data/all_jobs_node.csv", sep="\t")
all_df["datetime"] = pd.to_datetime(all_df["datetime"])
all_df = all_df.set_index(["datetime"])
all_df["evicted"] = all_df["id_job"].isin(evicted_df["id_job"])
app = Dash(__name__, server=server, routes_pathname_prefix="/dash/")
app.layout = html.Div(
[
html.Div(
className="row",
children=[
html.Div(
className="six columns",
children=[dcc.Graph(id="graph-with-dropdown")],
style=dict(width="75%"),
),
html.Div(
className="six columns",
children=[dcc.Graph(id="graph-with-dropdown2")],
style=dict(width="25%"),
),
],
style=dict(display="flex"),
),
html.Div(
className="row",
children=[
html.Div(
className="six columns",
children=[
dcc.Dropdown(
id="partition-dropdown",
options=[
"Partition (default is all)",
*all_df["partition"].unique(),
],
value="Partition (default is all)",
clearable=False,
searchable=False,
)
],
style={
"width": "50%",
"justify-content": "center",
},
),
html.Div(
className="six columns",
children=[
dcc.Dropdown(
id="node-dropdown",
options=[
"Number of Nodes (default is all)",
*sorted(
[
int(nodes)
for nodes in all_df["nodes_alloc"].unique()
]
),
],
value="Number of Nodes (default is all)",
clearable=False,
searchable=False,
)
],
style=dict(width="50%"),
),
],
style=dict(display="flex"),
),
]
)
init_callbacks(app, df, all_df)
return app.server
def init_callbacks(app, df, all_df):
#app.callback(
Output("graph-with-dropdown2", "figure"),
[Input("node-dropdown", "value"), Input("partition-dropdown", "value")],
)
def update_evicted_fig(selected_nodes, selected_partition):
if selected_nodes != "Number of Nodes (default is all)":
filtered_df = all_df[all_df["nodes_alloc"] == selected_nodes]
else:
filtered_df = all_df
if selected_partition != "Partition (default is all)":
filtered_df = filtered_df[filtered_df["partition"] == selected_partition]
x = ["Not Evicted", "Evicted"]
df1 = filtered_df.groupby(["evicted"]).count().reset_index()
fig = px.bar(
df1,
y=[
100
* filtered_df[filtered_df["evicted"] == False].size
/ filtered_df.size,
100
* filtered_df[filtered_df["evicted"] == True].size
/ filtered_df.size,
],
x=x,
color="evicted",
color_discrete_map={True: "red", False: "green"},
labels={"x": "Job Status", "y": "% of Jobs"},
)
fig.update_layout(transition_duration=500)
return fig
#app.callback(
Output("graph-with-dropdown", "figure"),
[Input("node-dropdown", "value"), Input("partition-dropdown", "value")],
)
def update_evicted_fig(selected_nodes, selected_partition):
if selected_nodes != "Number of Nodes (default is all)":
filtered_df = all_df[all_df["nodes_alloc"] == selected_nodes]
else:
filtered_df = all_df
if selected_partition != "Partition (default is all)":
filtered_df = filtered_df[filtered_df["partition"] == selected_partition]
print(
filtered_df[filtered_df["evicted"] == True]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"]
)
fig = px.bar(
x=filtered_df[filtered_df["evicted"] == False]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"]
.index,
y=filtered_df[filtered_df["evicted"] == False]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"],
labels={
"x": "Date",
"y": "Node hours",
},
title="Job Status",
barmode="stack",
)
fig.add_bar(
name="Evicted",
x=filtered_df[filtered_df["evicted"] == True]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"]
.index,
y=filtered_df[filtered_df["evicted"] == True]
.groupby([pd.Grouper(freq="6H")])
.sum(numeric_only=True)["node_hours"],
)
fig.update_layout(transition_duration=500)
return fig
return app.server
Is what I am hoping to do possible, and if so is there some documentation or a worked example someone could highlight for me?
I don't have you df so maybe you can refer my code to revise yours:
import pandas as pd
import numpy as np
import plotly.express as px
import dash
import dash_html_components as html
from dash import dcc
from dash_extensions.enrich import Input, Output, State, ServersideOutput
import dash_bootstrap_components as dbc
from dash.exceptions import PreventUpdate
df_2 = df[(df['BAS_DT'] >= '2022-01-01')]
df5 = df_2.pivot_table(values='USD_XC_BL',
index=['BAS_DT'],
aggfunc=np.sum).reset_index()
fig_3 = px.bar(df5,
x='BAS_DT',
y='USD_XC_BL',
labels='BAS_DT',
hover_name='BAS_DT', color_discrete_sequence=px.colors.qualitative.Alphabet)
fig_3.update_layout(xaxis_title="", yaxis_title="", plot_bgcolor='rgba(0,0,0,0)', margin=dict(l=0, r=0, t=0, b=0))
fig_3.update_xaxes(showline=False, showgrid=False),
fig_3.update_yaxes(showline=False, showgrid=False, separatethousands=True, tickformat=',.0f')
app = dash.Dash(__name__)
app.layout = html.Div([
dbc.Row([
dbc.Col([
dbc.Card([
dbc.CardBody([
dbc.Row([
dbc.Col([
html.H5('Amount by Currency', style={"text-align": "center"}),
dcc.Loading(children=[dcc.Graph(id='histogram_map', figure=fig_3)], color='#119DFF',
type='dot')
], width={'size': 12, 'offset': 0, 'order': 2}, style={"text-align": "left"}),
]),
])
]),
], xs=6),
dbc.Col([
dbc.Card([
dbc.CardBody([
dbc.Row([
dbc.Col([
html.H5('Overdue Status', style={"text-align": "center"}),
dcc.Loading(children=[dcc.Graph(id='overdue_map', figure={})], color='#119DFF', type='dot')
], width={'size': 12, 'offset': 0, 'order': 2}, style={"text-align": "left"}),
]),
])
]),
], xs=6),
], className='p-2 align-items-stretch')
])
#app.callback(
Output('overdue_map', 'figure'),
Input('histogram_map', 'clickData'))
def update_y_timeseries(clickData):
if clickData:
country_name = clickData['points'][0]['hovertext']
df_3 = df[df['BAS_DT'] == country_name]
df_4 = df_3.pivot_table(values='CLOC_CUR_XC_BL',
index=['APL_DTL_NAME'],
aggfunc=pd.Series.nunique).reset_index()
fig = px.bar(df_4,
x='APL_DTL_NAME',
y='CLOC_CUR_XC_BL'
, color_discrete_sequence=px.colors.qualitative.Alphabet)
fig.update_layout(xaxis_title="", yaxis_title="", plot_bgcolor='rgba(0,0,0,0)') # plot_bgcolor='rgba(0,0,0,0)'
fig.update_xaxes(showline=False, showgrid=False),
fig.update_yaxes(showline=False, showgrid=False, separatethousands=True)
fig.update_traces(width=0.3)
return fig
else:
raise PreventUpdate
if __name__ == "__main__":
app.run_server(debug=True)
I'm using clickData to return point as date, and then use this date to filter data and then make new bar graph.
Hope this help.

Data from Django-model not showing updates in Django dash app

import plotly.express as px
import pandas as pd
from django_plotly_dash import DjangoDash
from product.models import Products
app = DjangoDash("SimpleExample")
products = Products.objects.all()
to_dic = list(Products.objects.all().values("name", "price"))
keys_are = []
values_are = []
dictionary = {}
for i in to_dic:
keys_are.append(i["name"])
values_are.append(i["price"])
dictionary["name"] = keys_are
dictionary["price"] = values_are
opts = []
for i in to_dic:
opts.append({"label": i["name"], "value": i["price"]})
app.layout = html.Div(
[
html.Div(
children=[
html.Label("Products"),
dcc.Dropdown(id="pid", options=opts, value=values_are[0]),
],
style={"padding": 10, "flex": 1},
),
html.Div(id="gr_container", children=[]),
html.Br(),
dcc.Graph(id="pro_graph", figure={}),
],
)
#app.callback(
[
Output(component_id="pro_graph", component_property="figure"),
Output(component_id="gr_container", component_property="children"),
],
[
Input(component_id="pid", component_property="value"),
],
)
def update_graph(selected):
message = "The option selected is :{}".format(selected)
fig = px.bar(dictionary, x="name", y="price")
return fig, message
if __name__ == "__main__":
app.run_server(debug=True)
this is my dash-graph.py file in django project, when I run the project it show bar on dashboard, but when I update database i.e. the product model it does not update the bar and show the old graph until I run the server again, also the select box is just for testing no use for that here. Also is their a better way write this code, like the dictionary one.
moved it to update_graph function and it works
import plotly.express as px
import pandas as pd
from django_plotly_dash import DjangoDash
from product.models import Products
app = DjangoDash("SimpleExample")
app.layout = html.Div(
[
html.Div(
children=[
html.Label("Products"),
dcc.Dropdown(
id="pid",
),
],
style={"padding": 10, "flex": 1},
),
html.Div(id="gr_container", children=[]),
html.Br(),
dcc.Graph(id="pro_graph", figure={}),
],
)
#app.callback(
[
Output(component_id="pid", component_property="options"),
Output(component_id="pro_graph", component_property="figure"),
Output(component_id="gr_container", component_property="children"),
],
[
Input(component_id="pid", component_property="value"),
],
)
def update_graph(selected):
products = Products.objects.all()
to_dic = list(Products.objects.all().values("pk", "name", "price"))
keys_are = []
values_are = []
dictionary = {}
for i in to_dic:
keys_are.append(i["name"])
values_are.append(i["price"])
opts.append({"label": i["name"], "value": str(i["pk"])})
dictionary["name"] = keys_are
dictionary["price"] = values_are
opts = []
message = "The option selected is :{}".format(selected)
fig = px.bar(dictionary, x="name", y="price")
return opts, fig, message```

Why do all Dash components have borders when clicked?

I'm following a simple tutorial to build a stock price dashboard in Plotly Dash. When the app is running on localhost, every Component gets a border when hovered or clicked. See the GIF below.
Is this due to a setting somewhere? It's very annoying, and it seems to happen in most of the Dash apps I've been making.
The code for the app is here:
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.graph_objs as go
import pandas_datareader.data as web
from datetime import datetime, timedelta
app = dash.Dash(title="Stock Dashboard")
app.layout = html.Div(
[
html.H1("Stock Ticker Dashboard"),
html.Div(
[
html.H4("Enter stock symbols:"),
dcc.Input(
id = 'stock_picker',
value = 'AAPL',
style = dict(
fontSize = 24,
width = '100%',
marginRight = '15px',
padding = '10px 5px',
borderRadius = '4px'
)
),
],
style = dict(
display = 'inline-block',
verticalAlign = 'middle',
marginRight = '20px',
width = '40%'
)
),
html.Div(
[
html.H4("Choose a date range:"),
dcc.DatePickerRange(
id = 'date_picker',
min_date_allowed = datetime(2010, 1, 1),
max_date_allowed = datetime.today(),
start_date = datetime.today() - timedelta(days=365),
end_date = datetime.today(),
),
],
style = dict(
display = 'inline-block',
verticalAlign = 'middle',
marginLeft = '20px'
)
),
html.Div(
[
html.Button(
id = 'submit_button',
n_clicks = 0,
children = "Submit",
style = dict(
fontSize = 24,
marginLeft = '30px'
)
)
],
style = dict(
display = 'inline-block',
verticalAlign = 'bottom'
)
),
html.Div(
[
dcc.Graph(
id = 'stock_graph',
figure = dict(
data = [{'x': [1,2], 'y': [3,1]}],
layout = go.Layout(
xaxis = dict(
title = dict(
text = "Date",
),
),
yaxis = dict(
title = dict(
text = "Closing Price / [$]",
)
)
)
),
style = dict(
height = '600px'
)
)
],
style = dict(
height = '600px'
)
)
],
style = dict()
)
#app.callback(
Output('stock_graph', 'figure'),
[Input('submit_button', 'n_clicks')],
[
State('stock_picker', 'value'),
State('date_picker', 'start_date'),
State('date_picker', 'end_date')
],
)
def update_graph(n_clicks, stock_ticker, start_date, end_date):
start = datetime.strptime(start_date[:10], '%Y-%M-%d')
end = datetime.strptime(end_date[:10], '%Y-%M-%d')
print(f"Getting stock prices for: {stock_ticker}, [{start} - {end}]")
df = web.DataReader(stock_ticker, 'yahoo', start, end)
fig = dict(
data = [go.Scatter(
x = df.index,
y = df['Close'],
mode = 'lines'
)],
layout = dict(
title = stock_ticker,
yaxis = dict(
title = 'Closing Price / [$]'
)
)
)
return fig
if __name__ == '__main__':
app.run_server()
Edited to add the version numbers for some of the modules (please let me know if I should include others):
pandas==1.1.1
pandas-datareader==0.9.0
dash-core-components==1.10.2
dash-html-components==1.0.3
dash-renderer==1.6.0
dash-table==4.9.0
Flask==1.1.2
Flask-Compress==1.5.0
I'm a dingus. It was from my React Developer Tools addon (Firefox 79.0). Not sure why that setting got turned on, but there you go. :facepalm:

Categories

Resources