Development of Web Dashboard Visualizations with Python and Dash
Alberto García Robledo, Ph.D.
CentroGeo
Escuela de Verano CentroGeo 2021
Content
- What is Dash?
- Dash layouts
- Dash callbacks
- Third-party Dash components
- Exercises
Requirements
-
Knowledge
-
HTML and CSS (basic)
-
Python 3 (intermediate)
-
Pandas (basic)
-
-
Tools
-
A laptop with Internet connection
-
A Google e-mail account
-
Any OS (Windows, Linux, MacOS)
-
Any modern browser (Chrome, Firefox, Edge, Safari)
-
What is Dash?
What is Dash?
What is Dash?
-
Dash apps are rendered in the web browser
-
You can deploy your apps to servers and then share them through URLs
-
Dash is an open source library, released under the permissive MIT license
-
Available for Python, R, Julia, and .NET
Installation
-
In your terminal, install dash with pip:
pip install dash
-
If you prefer Jupyter notebook or JupyterLab as your development environment, install jupyter-dash:
pip install jupyter-dash
-
In this workshop we will use Google Colab
Dash Layouts
Dash layouts
-
Dash apps are composed of two parts:
-
The first part describes the layout
-
The second part describes the interactivity
-
-
Dash provides Python classes for all of the visual components of the application:
Example 1: Hello Dash
Example 1: Hello Dash
import dash_html_components as html
from jupyter_dash import JupyterDash
app = JupyterDash(__name__)
app.layout = html.Div(
html.H1('Hello Dash')
)
app.run_server()
Example 1 Take Aways
-
The dash_html_components library contains a component class for every HTML tag as well as keyword arguments for all of the HTML arguments
-
The layout is made out of nested Dash components:
-
A layout resembles the HTML DOM tree
-
-
The layout root is assigned to app.layout
Example 2: Hello Dash with Styles
Example 2: Hello Dash with Styles
from jupyter_dash import JupyterDash
import dash_html_components as html
EXTERNA_STYLESHEETS = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
BACKGROUND_COLOR = '#111111'
TEXT_COLOR = '#7FDBFF'
TEXT_ALIGN = 'center'
app = JupyterDash(__name__, external_stylesheets=EXTERNA_STYLESHEETS)
app.layout = \
html.Div(style={'backgroundColor': BACKGROUND_COLOR}, children=[
html.H1(children='Hello Dash', style={
'textAlign': TEXT_ALIGN,
'color': TEXT_COLOR
}),
html.Div(children='A Dash web app.', style={
'textAlign': TEXT_ALIGN,
'color': TEXT_COLOR
})
])
app.run_server()
Example 2 Take Aways
- The children of the HTML tag are specified through the children keyword argument
- The style property in Dash is a dictionary
- The keys in the style dictionary are camelCased
- So, instead of text-align, it's textAlign
- The HTML class attribute is className in Dash
Example 3: Markdown
- Markdown is a lightweight markup language for creating formatted text using a plain-text editor
Example 3: Markdown
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__name__, external_stylesheets=external_stylesheets)
markdown_text = '''
### Dash and Markdown
Dash apps can be written in Markdown.
Dash uses the [CommonMark](http://commonmark.org/)
specification of Markdown.
Check out their [60 Second Markdown Tutorial](http://commonmark.org/help/)
if this is your first introduction to Markdown!
'''
app.layout = html.Div([
dcc.Markdown(children=markdown_text)
])
app.run_server()
Example 3 Take Aways
-
While Dash exposes HTML through the dash_html_components library, it can be tedious to write your copy in HTML
-
For writing blocks of text, you can use the Markdown component in the dash_core_components library
Example 4: Hello Graph
Example 4: Hello Graph
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
EXTERNAL_STYLESHEETS = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
DATA = [
{
'x': [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012],
'y':[219, 146, 112, 127, 124, 180, 236, 207, 236, 263,
350, 430, 474, 526, 488, 537, 500, 439],
'name':'Rest of world',
'marker':{
'color': 'rgb(55, 83, 109)'
}
},
{
'x': [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012],
'y':[16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270,
299, 340, 403, 549, 499],
'name':'China',
'marker':{
'color': 'rgb(26, 118, 255)'
}
}
]
app = JupyterDash(__name__, external_stylesheets=EXTERNAL_STYLESHEETS)
figure = {
'data': DATA,
'layout': {
'title': 'US Export of Plastic Scrap',
'showlegend': True,
'legend': {
'x': 0,
'y': 1.0
},
'margin': {'l': 40, 'r': 0, 't': 40, 'b': 30}
}
}
app.layout = html.Div([
dcc.Graph(
figure=figure,
style={'height': 300},
)
])
app.run_server()
Example 4 Take Aways
-
The dcc.Graph component can be used to render any plotly-powered data visualization, passed as the figure argument
- The Plotly Graphing Library generates "figures".
- These are used in dcc.Graph with e.g. dcc.Graph(figure=fig) with fig a plotly figure
Dash Callbacks
Dash Callbacks
-
Custom behavior at the user interaction is defined by callbacks
-
Every Dash component in a layout has an unique id
-
A Dash callback has inputs and outputs
-
An input/output is associated to a component's id and a component's property
-
-
States are a special kind of input
Example 6: Simple Callback
Example 6: Simple Callback
import dash_html_components as html
import dash_core_components as dcc
from jupyter_dash import JupyterDash
from dash.dependencies import Input, Output
app = JupyterDash(__name__)
app.layout = html.Div([
html.Div(['Text:',
dcc.Input(id='text-input',
value='',
type='text')]),
html.Div(id='echo-div')
])
@app.callback(
Output('echo-div', 'children'),
Input('text-input', 'value')
)
def update_echo_div_callback(text_value):
if text_value:
return f'Echo: {text_value}'
app.run_server()
Example 6 Take Aways
-
You need to manually set a unique id to any component you want to refer to in a callback
-
A given Output can only have one callback
-
A given Input can have more than one callback, tho
-
All callbacks are triggered at the app startup
-
You need to manually check that inputs are not None
-
Example 7: Multiple Inputs and Outputs
Example 7: Multiple Inputs and Outputs
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
app = JupyterDash(__name__)
app.layout = html.Div([
dcc.Input(
id='x',
type='number',
value=1
),
dcc.Input(
id='c',
type='number',
value=0
),
html.Table([
html.Tr(html.Td(id='y-1-td')),
html.Tr(html.Td(id='y-2-td')),
html.Tr(html.Td(id='y-3-td')),
html.Tr(html.Td(id='y-4-td')),
html.Tr(html.Td(id='y-5-td'))
])
])
@app.callback(
Output('y-1-td', 'children'),
Output('y-2-td', 'children'),
Output('y-3-td', 'children'),
Output('y-4-td', 'children'),
Output('y-5-td', 'children'),
Input('x', 'value'),
Input('c', 'value'))
def compute_callback(x, c):
if (not x is None) and (not c is None):
return x*1+c, x*2+c, x*3+c, x*4+c, x*5+c
app.run_server(debug=True)
Example 8: States
Example 8: States
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
app = JupyterDash(__name__)
app.layout = html.Div([
dcc.Input(
id='name-input',
type='text',
value=''
),
dcc.Input(
id='lastname-input',
type='text',
value=''
),
dcc.Input(
id='age-input',
type='number',
value=18
),
html.Button(id='submit-button', children='Submit'),
html.Table([
html.Tr(html.Td(id='name-td')),
html.Tr(html.Td(id='lastname-td')),
html.Tr(html.Td(id='age-td'))
])
])
@app.callback(
Output('name-td', 'children'),
Output('lastname-td', 'children'),
Output('age-td', 'children'),
Input('submit-button', 'n_clicks'),
State('name-input', 'value'),
State('lastname-input', 'value'),
State('age-input', 'value'))
def compute_callback(n_clicks, name_input, lastname_input, age_input):
if n_clicks and name_input and lastname_input and age_input:
return name_input, lastname_input, age_input
else:
return '', '', ''
app.run_server()
Example 8 Take Aways
-
States allow us to gather values from components without triggering a callback
-
States allow us to pass extra values along with the trigger input values to a callback
-
Don't forget to provide default values for all outputs at startup time
Third-party Dash components
Third-party Dash components
-
Dash provides the tools to develop your own components
-
Dash components are basically Python wrappers of React.js components
-
Dash has a large community of developers of third-party open-source Dash components
dash-extensions
-
Provide various useful extensions to the Dash framework:
-
Multi-page Dash apps
-
Output groups allows to target an output multiple times in callbacks
-
Server-side outputs
-
Dash Bootstrap Components
-
Provides UI components based on the Bootstrap 4 framework:
-
Modal
-
Cards
-
Forms
-
Jumbotron
-
Navbar
-
Dash Sylvereye
-
Custom Dash library developed at CentroGeo
-
Visualization of large-scale street networks with WebGL
-
Customizable visualizations
-
Click events for junctions, roads, and markers
Example 9: Google Play Top
Example 9: Google Play Top
Example 9: Google Play Top
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
df = pd.read_csv(
'https://raw.githubusercontent.com/jasonchang0/kaggle-google-apps/master/google-play-store-apps/googleplaystore.csv', delimiter=',')
app = JupyterDash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
navbar = dbc.NavbarSimple(
brand="Google Play Top",
brand_href="#",
color="primary",
dark=True,
)
controls = dbc.Card(
[
dbc.FormGroup(
[
dbc.Label('Category'),
dcc.Dropdown(
id='category-dropdown',
options=[
{'label': col, 'value': col} for col in df['Category'].unique()
],
value='ART_AND_DESIGN',
),
]
),
dbc.FormGroup(
[
dbc.Label('Top'),
dcc.Dropdown(
id='top-dropdown',
options=[
{'label': 5, 'value': 5},
{'label': 10, 'value': 10},
{'label': 20, 'value': 20},
{'label': 30, 'value': 30},
{'label': 40, 'value': 40},
{'label': 50, 'value': 50},
],
value=5,
),
]
)
],
body=True
)
app.layout = dbc.Container(
[
navbar,
dbc.Row(
[
dbc.Col(controls, md=4),
dbc.Col(dcc.Graph(id='top-graph'), md=8),
],
align='center'
),
]
)
@app.callback(
Output('top-graph', 'figure'),
Input('category-dropdown', 'value'),
Input('top-dropdown', 'value')
)
def update_callback(category, top):
df2 = df[df['Category'] == category]
df2 = df2.sort_values(by='Rating', ascending=False).head(top)
fig = px.bar(df2, x='App', y='Rating')
return fig
app.run_server()
Example 6 Take Aways
-
You can use Pandas DataFrames as a data source of your Dash apps
-
Dash provides the Plotly Express module, which contains functions that can create entire figures at once
-
Dash Bootstrap Components provide the Navbar, Card, and FormGroup components, which are based on Boostrap 4
Activity: Visualizing Correlations
Activity: Visualizing Correlations
-
Pick a dataset from kaggle.com
-
Develop a simple Dash app that displays a Plotly Express scatterplot to visually explore potential correlations between any two numerical attributes
-
The dash app must use Dash Bootstrap Components for the UI: two columns and a navbar
Activity: Visualizing Correlations
Thank you!
agarcia@centrogeo.edu.mx
Taller Verano CentroGeo 2021
By Alberto Garcia-Robledo
Taller Verano CentroGeo 2021
- 0