Chapter 11: Advanced Components
Contents
Chapter 11: Advanced Components¶
What you will learn¶
Dash libraries include many components that serve multiple purposes. It may be a bit overwhelming to navigate through all the components in search for the one that meets your needs. Therefore, in this chapter we will provide an overview of several components that are commonly used and that you may find useful to include as your apps develop.
We will break down the components into categories, grouping together components that serve the same purpose. For each category, we will present some of the most common components in detail.
All components in this chapter come from these libraries:
Learning Intentions
Upload, Card, Modal, Alert components
Store data, Datepicker and Interval component
Tabs and Offcanvas components
By the end of this chapter you will know how to build this app:
See the code
# Import packages
from dash import Dash, Input, Output, State, html
import dash_core_components as dcc
import dash_bootstrap_components as dbc
import base64
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
image_filename = 'plotly.png' # replace with your own image
encoded_image = base64.b64encode(open(image_filename, 'rb').read())
img = html.Img(src='data:image/png;base64,{}'.format(encoded_image.decode()))
offcanvas_doc = dcc.Link("Off-Canvas documentation", id='oc_doc', target='_blank',href='https://dash-bootstrap-components.opensource.faculty.ai/docs/components/offcanvas/')
link_doc = dcc.Link("Link documentation", id='link_doc', target='_blank',href='https://dash.plotly.com/dash-core-components/link')
offcanvas_layout = dbc.Container(
[
dbc.Row([dbc.Col(img)]),
dbc.Row([dbc.Col(offcanvas_doc)]),
dbc.Row([dbc.Col(link_doc)]),
]
)
offcanvas = html.Div(
[
dbc.Button("Open Offcanvas", id="open-offcanvas", n_clicks=0),
dbc.Offcanvas(
[offcanvas_layout],
id="offcanvas",
title="Off-Canvas",
is_open=False,
),
]
)
# App Layout
app.layout = dbc.Container(
[
dbc.Row([dbc.Col(offcanvas)])
]
)
@app.callback(
Output("offcanvas", "is_open"),
Input("open-offcanvas", "n_clicks"),
)
def toggle_offcanvas(n1):
if n1:
return True
# Run the App
if __name__ == '__main__':
app.run_server()
11.1 Data Display Components¶
11.1.1 Upload¶
The Upload
component allows us to upload a file to the dashboard. For this example we will upload a CSV file and plot the data on a line chart. Download this CSV file, save it as rotation_angle.csv
, run the following code, and try uploading the file into the drag and drop section of the app.
Attention
Note that the update_fig()
callback function below is designed for CSV files exclusively. Different data wrangling inside the function would be required if you choose to work with other data files.
from dash import Dash, dcc, html, Input, Output, State
import dash_bootstrap_components as dbc
import pandas as pd
import plotly.express as px
import base64
import io
from dash.dash import no_update
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
upload = dcc.Upload(
id='upload-data',
children=html.Div([
'Drag & Drop or Click to Select CSV file'
]),
style={
'width': '100%',
'height': '10%',
'lineHeight': '60px',
'borderStyle': 'dashed',
'textAlign': 'center',
}
)
graph = dcc.Graph(id='graph1')
# App Layout
app.layout = dbc.Container(
[
dbc.Row(dbc.Col(upload)),
dbc.Row(dbc.Col(graph))
]
)
@app.callback(Output('graph1', 'figure'),
Input('upload-data', 'contents'))
def update_fig(contents):
if contents is not None:
content_type, content_data = contents.split(',')
# Check if data is CSV
if 'csv' in content_type:
decoded_data = base64.b64decode(content_data)
df = pd.read_csv(io.StringIO(decoded_data.decode('utf-8')))
fig = px.line(df, y='angle')
return fig
return no_update
# Run the app
if __name__ == '__main__':
app.run_server()
11.1.2 Card¶
The Card
component provides a container in which we can place content neatly such as: titles, main body text, images, graphs, buttons, and links. It often leads to a more appealing layout design. All you need to do is build the card body inside the dbc.Card
.
from dash import Dash, html
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
card = dbc.Card(
[
dbc.CardBody(
[
html.H4("Card title", className="card-title"),
html.P(
"Some quick example text to build on the card title and make up the bulk of the card's content.",
className="card-text",
)
]
),
],
style={"width": "18rem"},
)
app.layout = dbc.Container(
[
dbc.Row(dbc.Col([card])),
]
)
# Run the app
if __name__ == '__main__':
app.run_server()
Now let’s create a card with a graph and a dropdown.
from dash import Dash, html, dcc, Output, Input
import dash_bootstrap_components as dbc
import plotly.express as px
df = px.data.gapminder()
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
card = dbc.Card(
[
dbc.CardBody(
[
html.H4("population by country", className="card-title"),
dcc.Dropdown(df.country.unique(),
multi=True,
value=[df.country[0],df.country[20]],
id='my-dropdown'),
dcc.Graph(id='my-graph')
]
),
],
style={"width": "50rem"},
)
app.layout = dbc.Container(
[
dbc.Row(dbc.Col([card])),
]
)
@app.callback(
Output('my-graph','figure'),
Input('my-dropdown','value')
)
def update_graph_card(value):
dff = df[df.country.isin(value)]
fig = px.histogram(dff, 'country', y='pop')
return fig
if __name__ == '__main__':
app.run_server()
11.1.3 Modal¶
Modals
are pop-up boxes that allow for user notification, input, or other content to be displayed. A modal is often incorporated to draw the user’s attention to a specific section of the page. In the example below, the body of the modal solely contains text. However, just like the card, the modal body can contain many others elements within its children: dropdowns, graphs, input fields, images, links, etc.
from dash import Dash, Input, Output, State, html
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
open_button = dbc.Button("Open", id="open_modal")
close_button = dbc.Button("Close", id="close_modal")
modal = dbc.Modal(
[
dbc.ModalHeader(html.H1("Title")),
dbc.ModalBody("This is the content of the modal"),
dbc.ModalFooter(close_button),
],
id="modal",
is_open=False,
)
# App Layout
app.layout = dbc.Container(
[
dbc.Row(dbc.Col([open_button])),
dbc.Row(dbc.Col([modal]))
]
)
@app.callback(
Output("modal", "is_open"),
Input("open_modal", "n_clicks"), Input("close_modal", "n_clicks"),
State("modal", "is_open")
)
def toggle_modal(n1, n2, is_open):
if n1 or n2:
return not is_open
return is_open
# Run the app
if __name__ == '__main__':
app.run_server()
11.1.4 Alert¶
Alerts
are boxes that provide messages depending on the user interaction with the app.
Using the callback, you can update many of the component’s properties such as: color, fading animation, duration of appearance.
In the example below, an alert pops up if the user chooses a quantity over 100.
# Import packages
from dash import Dash, dcc, html, Input, Output
import dash_bootstrap_components as dbc
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# App Layout
app.layout = dbc.Container(
[
dbc.Row([
dbc.Col([
html.Label("Select the number of computers to purchase:"),
dcc.Dropdown([10, 44, 103], value=10, id='my-dropdown')
], width=4),
dbc.Col([
html.Div(id='content')
], width=6)
])
]
)
@app.callback(
Output("content", "children"),
Input("my-dropdown", "value"),
)
def toggle_offcanvas(value):
if value:
if value < 100:
return f"You have selected to purchase {value} computers."
if value > 100:
return dbc.Alert(children="We don't have so many computers in stock. Please select fewer computers",
color="danger")
else: no_update
# Run the app
if __name__ == '__main__':
app.run_server()
Let’s see a more sophisticated example. Below, we have created alerts depending on the GDP Per Capita of a selected country and year, compared to the global average:
If the country’s GDP Per Capita is greater than the world’s average, the alert message will have a green background
Otherwise, the message will become red
from dash import Dash, dcc, Input, Output, html
import dash_bootstrap_components as dbc
import plotly.graph_objects as go
import pandas as pd
import plotly.express as px
import numpy as np
# Import data
df = px.data.gapminder()
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Create app components
_header = html.H1(children='Alerts by GDP Per Capita', style={'textAlign' : 'center'})
_text1 = html.P(children='The below alert will adapt depending on GDP for the selected country and year, compared to the world\'s average GDP', style={'textAlign' : 'center'})
year_sel = dcc.Dropdown(id='year-dropdown', placeholder='Select a year', options=df.year.unique())
country_sel = dcc.Dropdown(id='country-dropdown', placeholder='Select a country', options=df.country.unique())
alert_msg = dbc.Alert(id='alert-gdp', children="Select a year and country to trigger alert", color="info")
# App Layout
app.layout = dbc.Container(
[
dbc.Row([dbc.Col([_header], width=8)]),
dbc.Row([dbc.Col([_text1], width=8)]),
dbc.Row([
dbc.Col([year_sel], width=4),
dbc.Col([country_sel], width=4)
]),
dbc.Row([dbc.Col([alert_msg], width=8)])
]
)
@app.callback(
Output("alert-gdp", "color"),
Output("alert-gdp", "children"),
Input("year-dropdown", "value"),
Input("country-dropdown", "value"),
prevent_initial_call=True
)
def update_alert(y, c):
gdp_sel = df.loc[(df['country']==c) & (df['year']==y), 'gdpPercap'] #Filter for selection
gdp_global_avg = df.loc[(df['year']==y), 'gdpPercap'] #Calculate world avg for the same year
if (gdp_sel.values.size > 0) & (gdp_global_avg.values.size > 0):
gdp_sel_v = round(gdp_sel.values[0],2)
gdp_avg_v = round(np.mean(gdp_global_avg.values),2)
new_children = ['The GDP per Capita in '+c+' in '+str(y)+' was: '+gdp_sel_v.astype(str)+
'; The world average was: '+gdp_avg_v.astype(str)]
if gdp_sel_v < gdp_avg_v:
new_color = 'danger'
else:
new_color = 'success'
else:
new_color = "dark"
new_children = 'Insufficient Data. Try another selection'
return new_color, new_children
# Run the app
if __name__ == '__main__':
app.run_server()
11.2 Date Filtering & Input Components¶
11.2.1 DatePicker¶
The DatePicker components allow the user to select a single date or a date range. There are two types of date pickers, both are part of the Dash Core Components library:
DatePickerSingle
consists of one single date selection: by clicking on the object a calendar will pop up, allowing the user to pick a date.DatePickerRange
is similar to the previous component, but includes two date selections, which should be read as “start” and “end” dates.
The two components have very similar properties. The main ones are:
min_date_allowed
: minimum date the user can choose frommax_date_allowed
: maximum date the user can choose fromstart_date
: default start date selected when app page initially loadsend_date
: default end date selected when app page initially loads
In the following app, a DatePickerRange is used as a filter for a line chart. Based on the user selection, a dataframe will be filtered inside the callback function and the chart will be updated.
Note
In the following app, instead of using the gapminder dataset, we have used a dataset based on stock prices, as it includes a full date field.
# Import packages
from dash import Dash, dcc, Input, Output, html
import dash_bootstrap_components as dbc
import pandas as pd
from datetime import date
import plotly.express as px
# Import data
df = px.data.stocks()
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Create app components
date_range = dcc.DatePickerRange(id='date-range',
start_date_placeholder_text='start date',
end_date_placeholder_text='end date',
min_date_allowed=df.date.min(),
max_date_allowed=df.date.max(),
display_format='DD-MMM-YYYY',
first_day_of_week = 1)
# App Layout
app.layout = dbc.Container(
[
dbc.Row([dbc.Col([date_range], width=8)]),
dbc.Row(dbc.Col([dcc.Graph(id='stock-line')], width=8))
]
)
# Configure callback
@app.callback(
Output(component_id='stock-line', component_property='figure'),
Input(component_id='date-range', component_property='start_date'),
Input(component_id='date-range', component_property='end_date')
)
def plot_dt(start_date, end_date):
df_plot = df
if start_date is not None:
df_plot = df_plot.loc[(df_plot['date']>=start_date), :]
if end_date is not None:
df_plot = df_plot.loc[(df_plot['date']<=end_date), :]
fig = px.line(df_plot, x='date', y=['GOOG','AAPL','AMZN','FB','NFLX','MSFT'], template='plotly_white')
return fig
# Run the App
if __name__ == '__main__':
app.run_server()
See additional properties and examples of the DatePickerRange
component.
11.2.2 Store¶
Store
component stores app data in the user’s browser. A typical use case for this component is to store data in memory and use it in a different tab.
When using this component, it is important to pay attention to the following:
this component can only store data in the following formats: JSON, list, dictionary data types. With the
data
property, we can access to the content stored in memory.how long the data is going to be stored is a customizable property called
storage_type
. We can use three different types of memory, which are cleared by three different events.memory
: the data will be cleared when we refresh the browser page;session
: the data will be cleared when we close the browser;local
: the data will be cleared when we clear the browser cookies.this is an invisible component: although it won’t affect app layout, the component must be included in the
app.layout
in order to work properly.it’s generally safe to store up to 2MB in most environments, and 5~10MB in most desktop-only applications.
In the following example, a dropdown selection is stored in memory. We’ve generated three different store components, one for each storage type. This should clarify the difference among the three memory types. In the app, the three graphs will plot life expectancy for the countries that are in the corresponding memory.
Try to run the app on your computer. Then, test the storage types by refreshing the page; then closing the browser and reopening it; and then clearing cookies.
Note
Don’t worry about understanding the code below. This was written for the purpose of demonstrating the different storage types.
# Import packages
from dash import Dash, dcc, Input, Output, html
from dash.exceptions import PreventUpdate
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
# Import data
df = px.data.gapminder()
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Create app components
_header = html.H1(children='Store App', style = {'textAlign' : 'center'})
_text1 = html.P(children='The selected countries below will be stored in memory', style = {'textAlign' : 'center'})
country_sel = dcc.Dropdown(id='country-dropdown', placeholder = 'Select countries', options = [c for c in df.country.unique()], multi=True)
mstorage = dcc.Store(id='memory', data=[], storage_type='memory')
sstorage = dcc.Store(id='session', data=[], storage_type='session')
lstorage = dcc.Store(id='local', data=[], storage_type='local')
_subheader41 = html.H4(children='Memory Store based chart', style = {'textAlign' : 'center'})
_subheader42 = html.H4(children='Session Store based chart', style = {'textAlign' : 'center'})
_subheader43 = html.H4(children='Local Store based chart', style = {'textAlign' : 'center'})
_subheader51 = html.H5(children='Memory Store content:', style = {'textAlign' : 'center'})
_subheader52 = html.H5(children='Session Store content:', style = {'textAlign' : 'center'})
_subheader53 = html.H5(children='Local Store content:', style = {'textAlign' : 'center'})
# App Layout
app.layout = dbc.Container(
[
dbc.Row([dbc.Col([_header], width=12)]),
dbc.Row([dbc.Col([_text1], width=12)]),
dbc.Row([dbc.Col([country_sel], width=12)]),
dbc.Row([
dbc.Col([_subheader41], width=4), dbc.Col([_subheader42], width=4), dbc.Col([_subheader43], width=4)
]),
dbc.Row([
dbc.Col([dcc.Graph(id='memory-life-exp-line')], width=4),
dbc.Col([dcc.Graph(id='session-life-exp-line')], width=4),
dbc.Col([dcc.Graph(id='local-life-exp-line')], width=4)
]),
dbc.Row([
dbc.Col([_subheader51], width=2),
dbc.Col([html.P(id='memory-output',)], width=2),
dbc.Col([_subheader52], width=2),
dbc.Col([html.P(id='session-output',)], width=2),
dbc.Col([_subheader53], width=2),
dbc.Col([html.P(id='local-output',)], width=2)
]),
mstorage, lstorage, sstorage
]
)
# Configure callbacks
## Generate callbacks, one per memory type
for store_type in ['memory', 'session', 'local']:
chart_type = store_type+"-life-exp-line"
output_type = store_type+"-output"
# Write in memory
@app.callback(Output(store_type, "data"),
Input("country-dropdown", "value"),
Input(store_type, "data"))
def write_memo(new_sel, memo):
if new_sel is None:
raise PreventUpdate # We avoid update the store if there is no selection or if a different memory was selected
else:
for c in new_sel:
if c not in memo:
memo.append(c)
return memo
## Update graphs
@app.callback(Output(chart_type, 'figure'),
Input(store_type, 'data'))
def plot_gen(memory_sel):
fig = px.line()
if memory_sel is not None:
df_plot = df.loc[(df['country'].isin(memory_sel)), :]
fig = px.line(df_plot, x='year', y='lifeExp', color='country', template='plotly_white')
return fig
## Output memory content
@app.callback(Output(output_type, "children"),
Input(store_type, "data"))
def print_memo(current_memory):
if current_memory is None:
output = ""
else:
output = ", ".join(current_memory)
return output
# Run the App
if __name__ == '__main__':
app.run_server()
Below is a real life example of how to use dcc.Store
in your app. In this example, we store the gapminder data session chosen in one tab to use it in another tab:
# Import packages
from dash import Dash, dcc, Input, Output, html, dash_table
from dash.exceptions import PreventUpdate
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# App Layout
app.layout = html.Div([
html.H1('Store App with Data', style = {'textAlign' : 'center'}),
dcc.Store(id='memo', data=[], storage_type='session'),
dcc.Tabs(id='store-example-data', value='tab-1-data-input', children=[
dcc.Tab(label='Tab One', value='tab-1-data-input'),
dcc.Tab(label='Tab Two', value='tab-2-data-store'),
]),
html.Div(id='tabs-content')
])
# Display tab content, based on the tab selected
@app.callback(Output('tabs-content', 'children'),
Input('store-example-data', 'value'))
def render_content(tab):
if tab == 'tab-1-data-input':
df = px.data.gapminder() # Data imported in tab 1
return html.Div([
html.H3('Select gapminder data to store in memory'),
dcc.Dropdown(id='country-dropdown', placeholder = 'Select a country', options = [c for c in df.country.unique()])
])
elif tab == 'tab-2-data-store':
return html.Div([
html.H3('Selected data from previous Tab'),
html.Div(id='data-table')
])
# save the filtered dataframe in dcc.Store once user selects dropdown option
@app.callback(Output('memo', 'data'),
Input('country-dropdown', 'value'))
def sel_records(c): # Write in memory
if c is None:
raise PreventUpdate
else:
df = px.data.gapminder() # Data imported in tab 1
recs = df.loc[(df['country']==c), :]
return recs.to_dict('records')
# retrieve the stored data to populate the DataTable shown in tab 2
@app.callback(Output('data-table', 'children'),
Input('memo', 'data'))
def show_records(data_): # Read from memory
data_df = pd.DataFrame(data_)
my_table = dash_table.DataTable(
columns=[{"name": i, "id": i} for i in data_df.columns],
data=data_df.to_dict('records')
)
return my_table
if __name__ == '__main__':
app.run_server()
See additional properties and examples of the Store
component.
11.2.3 Interval¶
Interval
enables automatic recurrent updates of the app, by triggering callbacks periodically.
One example where this component is typically used is when the app is connected to an API to download data that is repeatedly updated (e.g. stock market data). By adjusting properly, it is possible to configure the following:
interval
is a property that determines the refresh rate. This is measured in milliseconds and every time this interval expires, a counter is increased.max_intervals
can be configured to set a cap to the number of times the refresh happens. By default, this property is set to -1, meaning that refreshes will never stop.n_intervals
represent the counter, i.e. the number of times the interval has passed. This property is used to trigger the callback function.
This is an invisible component: although it won’t affect app layout, the component must be included in the app.layout
in order to work properly.
In the following example, the current time in New York is refreshed every 2 seconds for 7 times, and then the Interval is disabled, stopping the app from refreshing.
# Import packages
from dash import Dash, dcc, Input, Output, html, no_update
import dash_bootstrap_components as dbc
from dash.exceptions import PreventUpdate
from datetime import datetime
import pytz
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
_header1 = html.H1(children='Current Time', style={'textAlign': 'center'})
_header4 = html.H4(
children='The New York time below is refreshed whenever the interval component triggers the callback.',
style={'textAlign': 'center'})
_p = html.P(children='', id='livet',
style={'textAlign': 'center', 'font-family': 'Courier New',
'font-size': '250%'})
_interval = dcc.Interval(id='int1', disabled=False, interval=2000)
# App Layout
app.layout = dbc.Container(
[
_interval,
dbc.Row([dbc.Col([_header1], width=12)]),
dbc.Row([dbc.Col([_header4], width=12)]),
dbc.Row([dbc.Col([_p], width=12)])
]
)
# Configure callback
@app.callback(
Output("livet", "children"),
Output("int1", "disabled"),
Input("int1", "n_intervals"),
prevent_initial_call=True
)
def refresh_time(i):
if i == 0:
raise PreventUpdate # Prevent the callback from updating when the app first loads (n_intervals==0)
elif i<8:
tz = pytz.timezone('America/New_York')
now = datetime.now(tz).strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
return now, False
else:
return no_update, True
# Run the app
if __name__ == '__main__':
app.run_server()
Exercises¶
(1) Build an app composed of a title, a DatePickerRange
component, and 3 Card
components.
Using the
px.data.stocks()
data, build the same graph in each of the 3 cards: a line chart with date on the x-axis and a list of stock prices on the y-axis for stocksGOOG
andAAPL
.Assign to the
DatePickerRange
’sstart_date
prop thedate(2018, 5, 1)
, and assign to theend_date
prop thedate(2019, 2, 1)
.The callback should filter the data, based on the dates selected, with the goal that:
the left card should show any dataframe prior to the start date;
the central card graph should show the records which fall in the date range;
the right card should show any data after the end date.
See Solution
# Import packages
from dash import Dash, dcc, Input, Output, html
import dash_bootstrap_components as dbc
import pandas as pd
from datetime import date
import plotly.express as px
# Import data
df = px.data.stocks()
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Create app components
title_ = dcc.Markdown(children='Exercise 11.1', style={'textAlign': 'center','fontSize': 20})
date_range_ = dcc.DatePickerRange(id='date-range',
start_date_placeholder_text='start date',
end_date_placeholder_text='end date',
min_date_allowed=df.date.min(),
max_date_allowed=df.date.max(),
start_date=date(2018, 5, 1),
end_date=date(2019, 2, 1),
display_format='DD-MMM-YYYY',
first_day_of_week = 1)
card_L = dbc.Card(
dbc.CardBody([
dcc.Graph(id='my-graph-left'),
]),
)
card_C = dbc.Card(
dbc.CardBody([
dcc.Graph(id='my-graph-center'),
]),
)
card_R = dbc.Card(
dbc.CardBody([
dcc.Graph(id='my-graph-right'),
]),
)
# App layout
app.layout = dbc.Container(
[
dbc.Row(dbc.Col([title_], width = 12)),
dbc.Row(dbc.Col([date_range_], width = 12, style={'textAlign': 'center'})),
dbc.Row([
dbc.Col([card_L], width = 4),
dbc.Col([card_C], width = 4),
dbc.Col([card_R], width = 4)
]),
]
)
# Callbacks
@app.callback(
Output('my-graph-left','figure'),
Output('my-graph-center','figure'),
Output('my-graph-right','figure'),
Input(component_id='date-range', component_property='start_date'),
Input(component_id='date-range', component_property='end_date')
)
def plot_dt(start_date, end_date):
figL = px.line(df.loc[df['date']<start_date, :], x='date', y=['GOOG','AAPL'], template = 'plotly_dark')
figC = px.line(df.loc[(df['date']>=start_date) & (df['date']<=end_date), :], x='date', y=['GOOG','AAPL'], template = 'plotly_dark')
figR = px.line(df.loc[df['date']>end_date, :], x='date', y=['GOOG','AAPL'], template = 'plotly_dark')
return figL, figC, figR
# Run the App
if __name__== '__main__':
app.run_server()
(2) Build a new up with a title and 2 Tabs. Display the content of the following tabs through a callback:
The first tab should contain the app developed in the exercise 1 of this chapter
While the second tab should contain the app we built in the exercise 2 from chapter 8
See Solution
# Import packages
from dash import Dash, dcc, Input, Output, html
import dash_bootstrap_components as dbc
import pandas as pd
from datetime import date
import plotly.express as px
# Import data
df = px.data.stocks()
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
dfG = px.data.gapminder()
dfG = dfG.groupby(['year','continent']).agg({'pop':'sum', 'gdpPercap':'mean','lifeExp':'mean'}).reset_index()
# Initialise the App
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
# Create app components
title_ = dcc.Markdown(children='Exercise 11.2', style={'textAlign': 'center','fontSize': 20})
tabs_ = dcc.Tabs(
id='tabs-app-solution2',
children=[
dcc.Tab(label='App One', value='tab-app-1'),
dcc.Tab(label='App Two', value='tab-app-2')],
value='tab-app-1'
)
tabs_content_ = dbc.Container(id='tabs-content-solution2')
# Specific for App 1
date_range_ = dcc.DatePickerRange(id='date-range-solution2',
start_date_placeholder_text='start date',
end_date_placeholder_text='end date',
min_date_allowed=df.date.min(),
max_date_allowed=df.date.max(),
start_date=date(2018, 5, 1),
end_date=date(2019, 2, 1),
display_format='DD-MMM-YYYY',
first_day_of_week = 1)
card_L = dbc.Card(
dbc.CardBody([
dcc.Graph(id='my-graph-left-solution2'),
]),
)
card_C = dbc.Card(
dbc.CardBody([
dcc.Graph(id='my-graph-center-solution2'),
]),
)
card_R = dbc.Card(
dbc.CardBody([
dcc.Graph(id='my-graph-right-solution2'),
]),
)
# Specific for App 2
dropdown_ = dcc.Dropdown(id='metric-dropdown-solution2', placeholder = 'Select a metric',
options= [{'label': 'Population', 'value': 'pop'},
{'label': 'GDP per capita', 'value': 'gdpPercap'},
{'label': 'Life Expectancy', 'value': 'lifeExp'}],
value='gdpPercap',
clearable=False)
graph_ = dcc.Graph(id='figure1-solution2')
# App layout
app.layout = dbc.Container(
[
dbc.Row(dbc.Col([title_], width = 12)),
dbc.Row(
dbc.Col([
tabs_,
tabs_content_
],
width = 12)
)
]
)
# Callbacks
@app.callback(
Output('tabs-content-solution2', 'children'),
Input('tabs-app-solution2', 'value')
)
def render_content(tab):
if tab == 'tab-app-1':
app1_layout = dbc.Container(
[
dbc.Row(dbc.Col([date_range_], width = 12, style={'textAlign': 'center'})),
dbc.Row([
dbc.Col([card_L], width = 4),
dbc.Col([card_C], width = 4),
dbc.Col([card_R], width = 4)
]),
]
)
return app1_layout
elif tab == 'tab-app-2':
# App 2 layout
app2_layout = dbc.Container(
[
dbc.Row(
[
dbc.Col([dropdown_], width=2),
dbc.Col([graph_], width=10),
]
)
]
)
return app2_layout
# Callback for App1
@app.callback(
Output('my-graph-left-solution2','figure'),
Output('my-graph-center-solution2','figure'),
Output('my-graph-right-solution2','figure'),
Input(component_id='date-range-solution2', component_property='start_date'),
Input(component_id='date-range-solution2', component_property='end_date')
)
def plot_dt(start_date, end_date):
figL = px.line(df.loc[df['date']<start_date, :], x='date', y=['GOOG','AAPL'], template = 'plotly_dark')
figC = px.line(df.loc[(df['date']>=start_date) & (df['date']<=end_date), :], x='date', y=['GOOG','AAPL'], template = 'plotly_dark')
figR = px.line(df.loc[df['date']>end_date, :], x='date', y=['GOOG','AAPL'], template = 'plotly_dark')
return figL, figC, figR
# Callback for App2
@app.callback(
Output('figure1-solution2','figure'),
Input('metric-dropdown-solution2', 'value'),
)
def update_markdown(metric_):
fig = px.bar(dfG, x='year', y=metric_, color='continent', template='plotly_dark')
return fig
# Run the App
if __name__== '__main__':
app.run_server()
Summary¶
In this chapter, we have gone through several components that can add functionalities to your app. There are additional components and examples in the Dash documentation. In addition, there are third-party libraries that have nice components such as the Dash Mantine Components; however, keep in mind that these are not maintained by Plotly.
This is the end of the section on Advanced Dash. In the next part, we will focus on polishing our Dash app through enhanced styling and improved app performance.