Python Dash Fundamentals
Overview
Teaching: 10 min
Exercises: 10 minQuestions
What is Dash?
How can I create a simple Dash app?
How do I prepare it for extension?
Objectives
Build your first Dash app
Dash - What is it?
Dash is an open source framework for data visualization interfaces and has been developed since 2017.
It has implementations for R and Julia, and is popular with data scientists and engineering as it off loads the need to learn how to build web apps from the ground up.
Dash is build on three core technologies;
- Python
- React.js
- Plotly.js
Dash does the heavy lifting for us, so we can focus on the data and how we want to analyze it.
Dash is used in enterprise and science.
- A dashboard to analyze trading positions in real-time
- A visualization of millions of Uber rides
- An interactive financial report
Let’s Build!
First we need to set up a directory to work in and our environment using virtualenv.
mkdir dash-dojo
virtualenv --python=python3 .env
source .env/bin/activate
With the environment ready we can install the libraries that we need.
pip install dash numpy plotly pandas
We are also going to prepare our app so it will be ready for deploymnet on AWS Elastic Beanstalk
In our directory let’s make a source directory and within that create two files. The first is __init__.py which informs the environment that this is a
directory with python files to source as modules.
Now unlike previous past Dojos where we make our main python file app.py, for use with AEB we name it application.py.
In application.py we can make our very simply Dash app.
from dash import Dash, html, dcc
import pandas
import plotly.express as px
app = Dash(__name__)
application = app.server
app.title = 'Dash Dojo'
app.layout = html.Div(
children=[
html.H1(children="Avocado Analytics",)
]
)
if __name__ == '__main__':
application.run(debug=True, port=8080)
Let’s break down what is going on here.
Dashinitialises an instance of the application.dccaka dash core components, enables interactive componentsfor our graphs, dropdowns sliders.htmlaka dash html components, allows access to the html tags.pandasis for the manipulation of data.plotly.expressis our quick presets for plots
Before we make a plot, we are just going to in effect generate a basic webpage.
The title will appear in the tab title of our browser.
app.layout is where all the business happens with defining the layout of the webapp.
Notice when we run the program, we use application.run rather than app.run as we would normally do, again a AEB nuance.
Key Points
Dash is a framework running in Python built on Flask.
It exploits the power of Plotly for visually appealing and interactive plots.
Dash Layout and Plot
Overview
Teaching: 10 min
Exercises: 10 minQuestions
I layout my Dash app?
How do I add a plot?
Objectives
Layout basics
A simple plot
So far using Dash we basically have the same result as Flask. But now we are going to add in a plot.
Avacado analytics
Pandas comes with some test data to use.
from dash import Dash, html, dcc
import pandas as pd
import plotly.express as px
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
app = Dash(__name__)
application = app.server
app.config.suppress_callback_exceptions = True
app.title = 'Dash Dojo'
app.layout = html.Div(
children=[
html.H1(children="Fruit Analytics",)
]
)
if __name__ == '__main__':
application.run(debug=True, port=8080)
Running through our steps with Pandas, we create a Dataframe that has 3 columns.
We can print this to the command line and we would get the following.
Fruit Amount City
0 Apples 4 SF
1 Oranges 1 SF
2 Bananas 2 SF
3 Apples 2 Montreal
4 Oranges 4 Montreal
5 Bananas 5 Montreal
We can then create the figure using plotly express, where we use the stock barchart method, with x axis being Fruit type, y axis being Amount, and bars coloured by city.
With the fig object generated we can put it into our layout.
app.layout = html.Div(children=[
html.H1(children='Fruit Analytics'),
html.Div(children='''
Dash: A web application framework for your data.
'''),
dcc.Graph(
id='example-graph',
figure=fig
)
])
A lot of the heavy lifting is removed as we make use of the Dash Core Components, and the Graph layout object, simply passing to it the figure object.
Key Points
We can make things a lot easier when we start using Dash Bootstrap.
More Dash Layout and Plot
Overview
Teaching: 10 min
Exercises: 10 minQuestions
Reuseable layout?
How can I add plots side by side?
Can I have tabs?
Objectives
More layout
Tabs
Let’s be efficient and and use functions to generate portions of our layout.
def generate_table(dataframe, max_rows=10):
return html.Table([
html.Thead(
html.Tr([html.Th(col) for col in dataframe.columns])
),
html.Tbody([
html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))
])
])
What we can see here is that the function generate_table to generate our layout markup, in this case it is
generating some html, in the form of a table, but this could also be Dash Core Components.
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.express as px
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
df = pd.read_csv('https://gist.githubusercontent.com/chriddyp/c78bf172206ce24f77d6363a2d754b59/raw/c353e8ef842413cae56ae3920b8fd78468aa4cb2/usa-agricultural-exports-2011.csv')
def generate_table(dataframe, max_rows=10):
return html.Table([
html.Thead(
html.Tr([html.Th(col) for col in dataframe.columns])
),
html.Tbody([
html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))
])
])
app = dash.Dash(__name__)
application = app.server
app.config.suppress_callback_exceptions = True
app.title = 'Dash Dojo'
app.layout = html.Div(children=[
html.H1(children='Fruit Analytics'),
html.Div(children='''
Dash: A web application framework for your data.
'''),
dcc.Graph(
id='example-graph',
figure=fig
),
html.H4(children='US Agriculture Exports (2011)'),
generate_table(df)
])
if __name__ == '__main__':
application.run(debug=True, port=8080)
Rows and Columns
Thus far our plots and tables have existed one on top of the other.
Let’s consider two ways to lay things out. The first uses standard Dash Core Components and HTML.
app.layout = html.Div([
html.Div(children=[
html.Label('Dropdown'),
dcc.Dropdown(['New York City', 'Montréal', 'San Francisco'], 'Montréal'),
html.Br(),
html.Label('Multi-Select Dropdown'),
dcc.Dropdown(['New York City', 'Montréal', 'San Francisco'],
['Montréal', 'San Francisco'],
multi=True),
html.Br(),
html.Label('Radio Items'),
dcc.RadioItems(['New York City', 'Montréal', 'San Francisco'], 'Montréal'),
], style={'padding': 10, 'flex': 1}),
html.Div(children=[
html.Label('Checkboxes'),
dcc.Checklist(['New York City', 'Montréal', 'San Francisco'],
['Montréal', 'San Francisco']
),
html.Br(),
html.Label('Text Input'),
dcc.Input(value='MTL', type='text'),
html.Br(),
html.Label('Slider'),
dcc.Slider(
min=0,
max=9,
marks={i: f'Label {i}' if i == 1 else str(i) for i in range(1, 6)},
value=5,
),
], style={'padding': 10, 'flex': 1})
], style={'display': 'flex', 'flex-direction': 'row'})
Using html.Div we have our two columns, and within each we have defined some Dropdowns using dcc, radio items, and input text box with a default entry, and a slider.
These components will be used later in callbacks and our interactive plots.
Style in our html component is exactly as we would define it using CSS.
Dash Bootstrap Components
While this is one way of defining out layout the other alternative is Dash Boostrap Components.
Let’s return to our plot and graph from previous examples but use dbc instead to control layout.
from dash import Dash, html, dcc
import pandas as pd
import plotly.express as px
import dash_bootstrap_components as dbc
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
df = pd.read_csv('https://gist.githubusercontent.com/chriddyp/c78bf172206ce24f77d6363a2d754b59/raw/c353e8ef842413cae56ae3920b8fd78468aa4cb2/usa-agricultural-exports-2011.csv')
def generate_table(dataframe, max_rows=10):
return html.Table([
html.Thead(
html.Tr([html.Th(col) for col in dataframe.columns])
),
html.Tbody([
html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))
])
])
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
application = app.server
app.config.suppress_callback_exceptions = True
app.title = 'Dash Dojo'
app.layout = dbc.Container(
[
html.H1(children='Fruit Analytics'),
html.Div(children='''
Dash: A web application framework for your data.
'''),
dbc.Row(
[
dbc.Col(dcc.Graph(
id='example-graph',
figure=fig
), md=4),
dbc.Col([
html.H4(children='US Agriculture Exports (2011)'),
generate_table(df)
], md=8)
],
)
], fluid=True,
)
if __name__ == '__main__':
application.run(debug=True, port=8080)
Now our app layout begins with a dbc.Container which is subject to the style sheet (and we can use many pre-exisitng ones!).
Within the container, the way we define the layout is similar to pure html, but how we can define dbc.Row and dbc.Col, and use these to structure our layout.
There is also the assumption that there are 12 columns that components can span, and we can either allow autosizing of these, or define the number used by each column component, or even define their sizes with respect to specific screen sizes.
Here we used md to denote a medium sized screen. width would allow us to use the whole screen no matter the device size. We can also note that when we resize the screen the plot and table reposition dynamically.
Markdown
Just like these lessons, we can write portions of our Dash app with Markdown
...
markdown_text = '''
### Dash Markdown
Here is some test using [CommonMark](http://commonmark.org/)
'''
...
app.layout = dbc.Container(
[
...
dcc.Markdown(children=markdown_text)
...
]
)
Tabs
Reusable, modular, code is of course always easier to maintain. A sprawling app layout all in one file is difficult to read and maintain.
Tabs is a good example of this
from pickletools import markobject
from dash import Dash, html, dcc
import pandas as pd
import plotly.express as px
import dash_bootstrap_components as dbc
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
df = pd.read_csv('https://gist.githubusercontent.com/chriddyp/c78bf172206ce24f77d6363a2d754b59/raw/c353e8ef842413cae56ae3920b8fd78468aa4cb2/usa-agricultural-exports-2011.csv')
def generate_table(dataframe, max_rows=10):
return html.Table([
html.Thead(
html.Tr([html.Th(col) for col in dataframe.columns])
),
html.Tbody([
html.Tr([
html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
]) for i in range(min(len(dataframe), max_rows))
])
])
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
application = app.server
app.config.suppress_callback_exceptions = True
app.title = 'Dash Dojo'
markdown_text = '''
# Dash Markdown
Here is some test using [CommonMark](http://commonmark.org/)
'''
tab1_content = dbc.Card(
dbc.CardBody(
[
html.P("This is Tab 1!"),
dbc.Col(
dcc.Graph(
id='example-graph',
figure=fig
), md=4),
]
)
)
tab2_content = dbc.Card(
dbc.CardBody(
[
html.P("This is Tab 2!"),
dbc.Col([
html.H4(children='US Agriculture Exports (2011)'),
generate_table(df)
])
]
)
)
app.layout = dbc.Container(
[
html.H1(children='Fruit Analytics'),
html.Div(children='''
Dash: A web application framework for your data.
'''),
dbc.Tabs(
[
dbc.Tab(tab1_content, label="Tab 1"),
dbc.Tab(tab2_content, label="Tab 2")
]
)
], fluid=True,
)
if __name__ == '__main__':
application.run(debug=True, port=8080)
Key Points
Dash Bootstrap to the Rescue
Interactive Plots
Overview
Teaching: 30 min
Exercises: 15 minQuestions
How can a Plot Respond to an Input
Objectives
Interactive Elements
Callbacks
So far, plots and diagrams, generated using plotly, have been static. But with Dash we can make these plots interactive.
Callbacks
To begin, we need to provide a means to give some sort of input for the dashboard. For starters let’s use a text input.
from dash import Dash, dcc, html, Input, Output
...
app.layout = dbc.Container(
[
...
html.Div([
"Input: ",
dcc.Input(id='my-input', value='initial value', type='text')
]),
html.Br(),
html.Div(id='my-output'),
dbc.Tabs(
...
)
]
)
We’ve created our input field but we now need to use that input to create some form of response on the dashboard.
@app.callback(
Output(component_id='my-output', component-property='children'),
Input(component_id='my-input', component-property='value')
)
def update_output(input_value):
return f'Output: {input_value}'
The app.callback decorator is defining the use of the function update_output and dynamically passing in and out of it values, or entire elements.
The dcc.Input is one such input, a field, with a defined initial value and type. But we can use others.
Figures and Sliders
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
app = Dash(__name__)
app.layout = html.Div([
dcc.Graph(id='graph-with-slider'),
dcc.Slider(
df['year'].min(),
df['year'].max(),
step=None,
value=df['year'].min(),
marks={str(year): str(year) for year in df['year'].unique()},
id='year-slider'
)
])
@app.callback(
Output('graph-with-slider', 'figure'),
Input('year-slider', 'value'))
def update_figure(selected_year):
filtered_df = df[df.year == selected_year]
fig = px.scatter(filtered_df, x="gdpPercap", y="lifeExp",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55)
fig.update_layout(transition_duration=500)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
If we look at our new layout (which uses no bootstrap components), we return to dcc.Graph the figure object created by the callback function.
Our input to that callback is dcc.Slider, with passes the value of the slider.
Multiple Inputs
Building on our example above we can generate a list of continents for use in the dropdown, and use the dropdown as a means to filter the data of the dataframe that is used to form the plot
from dash import Dash, dcc, html, Input, Output
import plotly.express as px
import pandas as pd
import numpy as np
df = pd.read_csv(
'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
continent = df.continent.unique()
continent = np.insert(continent, 0, 'All')
app = Dash(__name__)
app.layout = html.Div([
dcc.Graph(id='graph-with-slider'),
dcc.Slider(
df['year'].min(),
df['year'].max(),
step=None,
value=df['year'].min(),
marks={str(year): str(year) for year in df['year'].unique()},
id='year-slider'
),
dcc.Dropdown(continent, id='continent_choice', value='All')
])
@app.callback(
Output('graph-with-slider', 'figure'),
Input('year-slider', 'value'),
Input('continent_choice', 'value'))
def update_figure(selected_year, continent_choice):
filtered_df = df[df.year == selected_year]
if continent_choice == 'All':
filtered_df2 = filtered_df
else:
filtered_df2 = filtered_df[filtered_df.continent == continent_choice]
fig = px.scatter(filtered_df2, x="gdpPercap", y="lifeExp",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55)
fig.update_layout(transition_duration=500)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Key Points
???