View of Mt. Fuji (3776 m) from Mt. Kumotori (2017 m).

Building a Dashboard App using Plotly’s Dash: A Complete Guide from Beginner to Pro

Complete guide to build an interactive dashboard App with Dash and deploy it to Heroku, Part 2: callbacks, authentication and Heroku deployment

Dayal Chand Aichara
Analytics Vidhya
Published in
9 min readNov 26, 2019

--

In part 1, we learnt how to start with Dash, add dash components, improve graph layout, and define callbacks. In part-2, we will learn how to add multiple tabs, share data between callbacks, write multi outputs callback, do user authentication, and deploy app to Heroku.

I will start from where we left in part-1. If you missed part-1, please read it.

Dashboard App

7. Tabs and data sharing between callbacks

Assume we want to make charts of different price technical indicators for given cryptocurrency. For this, we will add tabs to our app layout and modify app.callback for graph so it returns chart for selected tab.

we have extracted data for table and graph separately till now. But we should only extract price data once for all the callbacks to save time and computation. So we need to share data between callbacks. To make data sharing easy, we will write an another app.callback which will take input from Dropdown and give a json data file as output. Output of this callback will be shared with other callbacks.

7.1 Tabs

I will add tabs above the graph in app.layout .

tabs_styles = {
'height': '51px'
}
tab_style = {
'borderBottom': '1px solid #d6d6d6',
'padding': '2px',
'fontWeight': 'bold'
}

tab_selected_style = {
'borderTop': '1px solid #d6d6d6',
'borderBottom': '1px solid #d6d6d6',
'backgroundColor': 'black',
'color': 'yellow',
'padding': '10px'
}
dcc.Tabs(id="all-tabs-inline", value='tab-1', children=[
dcc.Tab(label='Simple Moving Average', value='tab-1', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Volatility Index', value='tab-2', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Relative Strength Index', value='tab-3', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Moving Average Divergence Convergence', value='tab-4', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Exponential Moving Average', value='tab-5', style=tab_style, selected_style=tab_selected_style),
dcc.Tab(label='Bollinger Bands', value='tab-6', style=tab_style,
selected_style=tab_selected_style),
], style=tabs_styles,
colors={
"border": "yellow",
"primary": "red",
"background": "orange"
}),

I have added 6 taps for 6 indicators. In above code, tab_style , tab_selected_style , and tabs_styles are predefined styles for general tab appearance, tab appearance after selection, and tab line appearance.

Tabs

7.2 Data

We need data to create charts and data table. We will use PriceIndices python package to get price data and calculate technical indicators. Let’s write a script ( data.py) to get data in dashboard_demo directory.

data.py

data.py will give us a pandas DataFrame which have all data required for charts.

7.3 Callbacks and data sharing

We add a new callback to get data.

  • Data callback
# import get_coin_data function from data.py
from data import get_coin_data
@app.callback(Output('intermediate-value', 'children'),
[Input('dropdown', 'value')])
def get_data(option): # option from drop down
df = get_coin_data(crypto=option, save_data=True)
return df.to_json(date_format='iso', orient='split')

Now modify data table callback and graph callback.

  • DataTable callback
@app.callback(Output('table-output', 'children'), 
[Input('intermediate-value', 'children')])
def get_data_table(data):
df = pd.read_json(data, orient='split')
df['date'] = pd.to_datetime(df['date'])
data_table = dash_table.DataTable(
id='datatable-data',
data=df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in df.columns],
style_table={'overflowY': 'scroll'},
fixed_rows={'headers': True, 'data': 10},
style_cell={'width': '100px'},
style_header={
'backgroundColor': 'rgb(230, 230, 230)',
'fontWeight': 'bold'
}
)
return data_table
  • Graph callback
Graph callbacks

DataTable and Graph callbacks sharing data from Data callback. Output of Data callback is used as input to DataTable and Graph callbacks. Graph callback function make a graph based on tab selection. Some graphs have two y-axis for better graph appearance. yaxis2 define style of second y-axis. I have explained app work flow in flowchart below.

Flowchart-2

Refresh the app page to see changes we made. Also try different coin, date range, and tab to see how do they alter the results.

8. Multi outputs callback

We have 3 callbacks till now. How about making a single app.callback of DataTable and Graph callbacks which gives multiple outputs? Sounds cool? Let’s do it.

We will combine Graph, and DataTable callbacks which will gives two outputs: Graph and DataTable. We can also combine Data callback with other two but if we do that, data will be a requested for each tab or date range or coin selection. We should only make data request once for coin selection and only for coin input change.

multi outputs callback

Note: If we put outputs in a list in “app.callback" , callback function must return a list of outputs.

Flowchart-3 explains input and output flow after combining two callbacks.

Flowchart-3

9. User Authentication

Dash provide user authentication through a separate python package dash-auth . dash-auth offers two methods of authentications: HTTP Basic Auth and Plotly OAuth.

9.1 HTTP Basic Auth

HTTP Basic Auth is one of the simplest forms of authentication on the web but it has few limitations.

  • Users can not log out of applications
  • You are responsible for sending the usernames and passwords to your viewers over a secure channel
  • Your viewers can not create their own account and cannot change their password
  • You are responsible for safely storing the username and password pairs in your code.

We need to add user and password in source code for HTTP Basic Auth. I will add HTTP Basic Auth code to “app.py”. It is advised to save user and password details in a separate file.

import dash
import dash_auth
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
app.config.suppress_callback_exceptions = True

VALID_USERNAME_PASSWORD_PAIRS = {
'dash_demo': 'dash@demo'
}

auth = dash_auth.BasicAuth(
app,
VALID_USERNAME_PASSWORD_PAIRS
)

When we rerun or refresh app page, there will be an authentication pop-up.We need to authenticate app only once.

Authentication pop-up

9.2 Plotly OAuth

A paid Plotly subscription account is required for Plotly Auth. Plotly 0Auth provides authentication through a registered online Plotly account or through a company’s Plotly Enterprise server.

See Plotly OAuth example here.

10. Login and Logout Buttons

In this section, I will demonstrate how to use Login and Logout Buttons for authentication. We can protect outputs of callbacks through user authentication.

Remove HTTP Basic Auth from “app.py” before proceeding.

Follow the steps written below to achieve authentication with Login and Logout buttons.

I. Create a “user.py” indashboard_demo directory which contains users and passwords.

user_pwd = {'dash': 'dash@123',
'dash1': 'dash1@123',
}
user_names = {'dash': 'User1, welcome to the crypto indicators dashboard',
'dash1': 'User1, welcome to the crypto indicators dashboard',
}

def users_info():
return user_pwd, user_names

II. Write Login route

Login route verify user and password combination and redirect to a url based on authentication results.

import flask
from users import users_info
user_pwd, user_names = users_info()
_app_route = '/'
# Create a login route
@app.server.route('/login', methods=['POST'])
def route_login():
data = flask.request.form
username = data.get('username')
password = data.get('password')

if username not in user_pwd.keys() or user_pwd[username] != password:
return flask.redirect('/login')
else:

# Return a redirect with
rep = flask.redirect(_app_route)

# Here we just store the given username in a cookie.
# Actual session cookies should be signed or use a JWT token.
rep.set_cookie('custom-auth-session', username)
return rep

III. Define a Login form

# Simple dash component login form.
login_form = html.Div([
html.Form([
dcc.Input(placeholder='username', name='username', type='text'),
dcc.Input(placeholder='password', name='password', type='password'),
html.Button('Login', type='submit')
], action='/login', method='post')
])

IV. Add buttons to app.layout before DateRangePicker

html.Div(id='custom-auth-frame'),
html.Div(id='custom-auth-frame-1',
style={
'textAlign': 'right',
"background": "black",
}
),

V. Create a Logout route

Logout route redirects to Login page when user click Logout button.

# create a logout route
@app.server.route('/logout', methods=['POST'])
def route_logout():
# Redirect back to the index and remove the session cookie.
rep = flask.redirect('/login')
rep.set_cookie('custom-auth-session', '', expires=0)
return rep

VI. Edit multi outputs callback

multi outputs callbacks

This updated callback will produce three outputs based on authentication results. Callback function will verify user and password combination, if authentication fails, it will redirect to login page, otherwise graph, and data table will be displayed. We will write LogoutButton inside the callback function.

Our app is password protected now. Let’s have a tour of what we build till now.

Dashboard tour video.

Everything looks fine.There is lot you can do with Dash as per your requirements. Read more use cases and tutorials here.

11. Deploying to Heroku

Disclaimer: Procedure written below is tested on MacBook Pro. It should work fine on Linux but may not work on Windows. Please follow instruction for window here: https://devcenter.heroku.com/articles/heroku-cli

Follow the procedure written below to deploy Dash app to Heroku.

I. Sign Up a free Heroku account.

II. Install Heroku command Line Interface (CLI) with brew tap heroku/brew && brew install heroku on mac or linux.

III. Initiate a GitHub repository with git init command.

IV. Write Procfile and .gitignore file in dashboard_demo directory as below.

Procfile

web: gunicorn index:server

.gitignore

*.pyc
.DS_Store

Your dashboard_demo directory should look like below.

dashboard_demo
|--.gitignore
|--app.py
|--index.py
|--Procfile
|--requirements.txt
|--users.py

V. Login to Heroku through CLI with command heroku login and run following commands to create and deploy an app.

$ heroku create dash-app-name # change dash-app-name to a unique name
$ git add . # add all files to git
$ git commit -m 'Initial app commit'
$ git push heroku master # deploy code to heroku
$ heroku ps:scale web=1 # run the app with a 1 heroku "dyno"

Now, you be able to see your app at https://dash-app-name.herokuapp.com.

I have created an app on Heroku with name crypto-indicators-dashboard . This is the same app we have created in this tutorial (Part-1 and part-2).

VI. If you make any change in code, do following to update app.

$ git add . # add changes
$ git commit -m 'change description'
$ git push heroku master # push to heroku

You should be able to build and deploy app to Heroku now if you have followed all the steps. You may run into deployment error, therefore try to deploy simple app first. Also check recent app logs with heroku logs --tail command to check app/code error.

You can do a lot with Dash.You can have multiple charts on same page, have sub tabs, decorate data table for specific values, make a data table download button etc. For this tutorial, I just wanted to make a dashboard which shows price indicators chart for a given date range and cryptocurrency.

Summary

  • First know and understand your requirements for dashboard.
  • Start app with simple layout and callbacks.
  • Add dash components and callbacks one by one.
  • Refresh app page on local host after addition or deletion to see changes.
  • Write separate codes for app, index, data, users etc to make it easy to debug and understand.
  • Experiment with different style and app layout for better appearance.
  • Share data between callbacks and use multiple outputs callbacks.
  • Test app on your local before deployment.
  • Deploy a simple app first and then scale.

Let me know how your first experience with Dash. 😉

You can find this app on Github.

Thank you for reading! 😊

I am always available to answer your queries, please reach out to me on LinkedIn or Twitter.

If you want to add Google Analytics tracking, favicon, custom CSS file etc to your Dash App, read part 3.

References/Resources:

  1. https://dash.plot.ly/?_ga=2.113607566.828752419.1574214165-1322431847.1545115553
  2. https://plot.ly/dash/
  3. https://towardsdatascience.com/how-to-build-a-complex-reporting-dashboard-using-dash-and-plotl-4f4257c18a7f
  4. https://devcenter.heroku.com/articles/heroku-cli

--

--

Dayal Chand Aichara
Analytics Vidhya

Data Scientist at KPMG Ignition Tokyo , Blockchain Enthusiast, Traveller, Trekker — https://www.linkedin.com/in/dcaichara/