Create A Financial Dashboard Learn How To Share States Across Callbacks

A guide for myself and others on how to use python, dash, plotly to create your very own financial dashboard

This is a new feature to the “Create A Financial Dashboard From Yahoo Finance With Python”. The idea is pretty straightforward.

The user clicks on the buttons to filter data according to the date. Now the only problem that I have encountered when trying to implement this feature was how to share state across multiple callback functions.

There are a couple of tricks.

However, I have found that the easiest way to implement is to create a hidden div with json data. Then in another callback, we can access that json through that div.

Let’s get started.

If you had read my previous post, “Create A Financial Dashboard From Yahoo Finance With Python”, you have familiarized yourself through the basic syntax of dash and plotly. So this time I won’t get into so much detail.

So after you have gone and read and gotten the app running, let’s go and add in some code.

In the layout, we will add some buttons. Here’s what my layout looks like.

app.layout = html.Div([
html.Div(id='hidden_stock_values', style={'display': 'none'}),
html.Div(["Input: ",
dcc.Input(id='my-input', value='', type='text', placeholder="symbol...")]),
html.Br(),
html.Div(id='my-output'),
html.Button("Submit", id="submit-button", n_clicks=0),
html.Br(),
html.Button("5D", id="5D_button", n_clicks_timestamp=-1),
html.Button("1M", id="1M_button", n_clicks_timestamp=-1),
html.Button("6M", id="6M_button", n_clicks_timestamp=-1),
html.Button("1Y", id="1Y_button", n_clicks_timestamp=-1),
html.Button("3Y", id="3Y_button", n_clicks_timestamp=-1),
dcc.Graph(id="output-graph"),
])

The n_clicks_time_stamp is for deciding which button was clicked most recently. And you might also notice that I have put a div with the id “hidden_stock_values” as well.

Then we will follow by editing the first call-back function. This will allows us to store data in a hidden div.

@app.callback(
Output(component_id='hidden_stock_values', component_property='children'),
[Input(component_id='submit-button', component_property='n_clicks')],
[dash.dependencies.State(component_id="my-input", component_property="value")],
)
def update_df(n_clicks, input_value):
tech_stocks = input_value
today = date.today()
yahoo_financials_tech = YahooFinancials(tech_stocks)
df = yahoo_financials_tech.get_historical_price_data('2017-01-01', str(today), "daily")
df = pd.DataFrame.from_dict(df[tech_stocks]["prices"])
return df.to_json()

Once we have set up data that can be accessed, let’s go to the next call-back. This one will graph the figure using a selected range from the buttons that were clicked.

@app.callback(
Output("output-graph", "figure"),
Input("hidden_stock_values", "children"),
Input("5D_button", "n_clicks_timestamp"),
Input("1M_button", "n_clicks_timestamp"),
Input("6M_button", "n_clicks_timestamp"),
Input("1Y_button", "n_clicks_timestamp"),
Input("3Y_button", "n_clicks_timestamp"),
)
def graph_by_date_button(jsonified_cleaned_data, timestamp1, timestamp2, timestamp3, timestamp4, timestamp5):
today = date.today()
def deal_with_sat_sun(today):
day_of_week = calendar.day_name[today.weekday()]
if day_of_week == "Saturday":
today = today - timedelta(1)
elif day_of_week == "Sunday":
today = today - timedelta(2)
return today
today = deal_with_sat_sun(today)
max_timestamp = max([timestamp1, timestamp2, timestamp3, timestamp4, timestamp5])
min_timestamp = min([timestamp1, timestamp2, timestamp3, timestamp4, timestamp5])
if min_timestamp == max_timestamp:
# no button has been clicked
# default it to the last 30 days
previous = today - timedelta(30)
elif timestamp1 == max_timestamp:
# 5D button has been clicked most recently
previous = today - timedelta(5)
elif timestamp2 == max_timestamp:
# 1M button has been clicked most recently
previous = today - timedelta(30)
elif timestamp3 == max_timestamp:
# 6M button has been clicked most recently
previous = today - timedelta(180)
elif timestamp4 == max_timestamp:
# 1Y button has been clicked most recently
previous = today - timedelta(365)
elif timestamp5 == max_timestamp:
# 3Y button has been clicked most recently
previous = today - timedelta(730)

dff = pd.read_json(jsonified_cleaned_data)
df_slider_value = dff[dff['formatted_date'] > str(previous)]
fig = px.line(df_slider_value, x='formatted_date', y='close', labels={"formatted_date": "Time", "close": "Closing Price"})
return fig

Pretty long but very easy to understand. It is taking in a total of 6 inputs. One is the data that we are accessing and the other 5 are just 5 different buttons.

The first part of the callback function is composed of two logics.

The first one is if the date that we are accessing falls into either Saturday or Sunday, then if we access a 5 days range of stock would only give us 3 or 4 days respectively. We want 5 days!

The second logic is just choosing the “highest” n_clicks_timestamp to decide which was a button was clicked just now. And if all timestamps equals each other, which is the default state, we will output a 1-month range.

Then finally we just need to turn that json data into the good old data frame and return a figure so that Output can graph it in id “output-graph”.