Alberto García Robledo, Ph.D.
CentroGeo
Escuela de Verano CentroGeo 2021
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)
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
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 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:
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()
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
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()
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()
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
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()
The dcc.Graph component can be used to render any plotly-powered data visualization, passed as the figure argument
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
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()
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
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)
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()
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
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
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
Provides UI components based on the Bootstrap 4 framework:
Modal
Cards
Forms
Jumbotron
Navbar
Custom Dash library developed at CentroGeo
Visualization of large-scale street networks with WebGL
Customizable visualizations
Click events for junctions, roads, and markers
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()
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
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
agarcia@centrogeo.edu.mx