Plotly has been go-to the library for data visualization by many data scientists nowadays. It provides a very easy to use API for creating interactive charts using python. Dash is another library that provides dashboard building functionality by using plotly charts. It easily integrates plotly charts into the dashboard. Apart from plotly charts it also provides various HTML tags and widgets which can be included in making the dashboard more interactive. It also lets us specify various CSS and HTML properties into components in order to change the look and feel of the dashboard. We'll be creating a simple dashboard that has few widgets to change graphs. We'll be explaining step by step process on building a basic dashboard with widgets using Plotly and Dash.
Below is a list of steps that we'll follow in order to create a dashboard using Plotly & Dash.
We'll start by importing necessary libraries.
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
We'll be using three datasets mentioned below of which two are easily available from the scikit-learn library.
We'll be keeping each dataset as a pandas dataframe as explained below.
from sklearn.datasets import load_iris, load_wine
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df["FlowerType"] = [iris.target_names[target] for target in iris.target]
iris_df.head()
wine = load_wine()
wine_df = pd.DataFrame(data=wine.data, columns=wine.feature_names)
wine_df["WineType"] = [wine.target_names[target] for target in wine.target]
wine_df.head()
apple_df = pd.read_csv("datasets/AAPL.csv")
apple_df.head()
We'll first create individual charts using plotly as explained below.
The first chart that will be included at top of the dashboard is a line chart that will plot the date on X-axis and open/high/low/close prices for that date on Y-axis.
chart1 = go.Figure()
chart1.add_trace(go.Scatter(x=apple_df.Date, y=apple_df.Open,
marker={"color":"tomato"},
mode="lines"))
chart1.update_layout(height=500,
xaxis_title="Date",
yaxis_title="Price ($)",
title="Apple Stock Prices [Apr-2019-Mar-2020]")
chart1
The second chart which will be added to the dashboard is scatter plot showing the relationship between two ingredients of wine data. All the points of the scatter plot will be color-encoded by wine type as well.
chart2 = px.scatter(data_frame=wine_df,
x=wine.feature_names[0],
y=wine.feature_names[1],
color="WineType",
title="%s vs %s color-encoded by wine type"%(wine.feature_names[0], wine.feature_names[1]),
height=500,
)
chart2
The third chart that we'll be adding to the dashboard is a bar chart depicting the average size of flower measurement for each flower type. It'll display flower type on X-axis and average measurement on Y-axis.
iris_avg_by_flower_type = iris_df.groupby(by="FlowerType").mean().reset_index()
chart3 = px.bar(data_frame=iris_avg_by_flower_type,
x="FlowerType",
y=iris.feature_names[0],
height=500,
title="Avg %s Per Flower Type"%iris.feature_names[0],
)
chart3
Dash adds each chart as a Graph component into the dashboard. We'll first wrap each plotly chart into the Dash Graph
component. It'll also let us give id to the chart in order to identify it as part of the dashboard's HTML component which will later include in the layout of the dashboard. The Graph
component is available as a part of the dash_core_components
library which gets installed when installing dash using pip/conda. Each individual HTML components like Div, H1, etc are available as a part of the dash_html_components
library which also gets installed with a dash. We'll import it for future use.
import dash
import dash_core_components as dcc
import dash_html_components as html
graph1 = dcc.Graph(
id='graph1',
figure=chart1,
#className="eight columns"
)
graph2 = dcc.Graph(
id='graph2',
figure=chart2,
#className="five columns"
)
graph3 = dcc.Graph(
id='graph3',
figure=chart3,
#className="five columns"
)
We'll be creating four widgets for the dashboard as mentioned below.
All widgets creation classes as available as a part of dash_core_components
. Please find below code for each widget.
multi_select_line_chart = dcc.Dropdown(
id="multi_select_line_chart",
options=[{"value":label, "label":label} for label in ["Open", "Low", "High", "Close"]],
value=["Open"],
multi=True,
clearable = False
)
dropdown1_scatter_chart = dcc.Dropdown(
id="dropdown1_scatter_chart",
options=[{"value":label, "label":label} for label in wine.feature_names],
value=wine.feature_names[0],
className="six columns",
clearable = False
)
dropdown2_scatter_chart = dcc.Dropdown(
id="dropdown2_scatter_chart",
options=[{"value":label, "label":label} for label in wine.feature_names],
value=wine.feature_names[1],
className="six columns",
clearable = False
)
dropdown_bar_chart = dcc.Dropdown(
id="dropdown_bar_chart",
options=[{"value":label, "label":label} for label in iris.feature_names],
value=iris.feature_names[0],
clearable = False
)
Dashboard created using dash will be a web app that uses flask for handling each request. We'll need to create a dash app whose layout we'll be setting in the next step by integrating all charts, widgets, and HTML components. We can create a dash app by calling the Dash()
method from the dash library by passing it any external stylesheet if we want to give different look to the dashboard. We can also pass meta tags information to this method when creating an app.
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__,
external_stylesheets=external_stylesheets,
meta_tags=[{"name": "viewport", "content": "width=device-width"}]
)
Below we have included code to create the layout of the dashboard and setting that layout as the layout of the dash app created in the previous step. We have included the HTML H2
component at the top in order to give heading to the dashboard. We have then two rows in the dashboard where the first row consists of a line chart along with its multi-select and the second row has two charts with their respective widgets. We have used HTML Div
component in order to group things. We have combined all components into the final top Div
which has a total dashboard.
Dashboard main components:
We also have explicitly provided CSS properties as a part of className
attributes of the Div component. Here property provided as a part of the className
attribute refers to the class name defined in external CSS which was passed when creating a dash app in the previous step. It's used to set the width of Divs.
We can also explicitly specify other CSS properties not included in CSS files as a dictionary to the style
attribute of HTML components.
header = html.H2(children="Simple Dashboard With Widgets")
row1 = html.Div(children=[multi_select_line_chart, graph1], className="eight columns")
scatter_div = html.Div(children=[html.Div(children=[dropdown1_scatter_chart, dropdown2_scatter_chart], className="row") , graph2], className="six columns")
bar_div = html.Div(children=[dropdown_bar_chart, graph3], className="six columns")
row2 = html.Div(children=[scatter_div, bar_div], className="eight columns")
layout = html.Div(children=[header, row1, row2], style={"text-align": "center", "justifyContent":"center"})
app.layout = layout
The callbacks are important functions that link widgets with charts and also get called whenever the state of the widget changes. The dash
provides two classes named Input
and Output
for linking dashboard components.
Input
component attribute.We need to pass Input
and Output
as parameters of callback annotation. We need to annotate each callback function with @app.callback
annotation passing it Output
and Input
. We can pass more than one Input
as a list so that it'll monitor all those widgets and changes to any of them will result in calling this function. We need to create a function with a same number of parameters as a number of Input
given as a list in an annotation. The function will be given new values of those widgets whose attributes are mentioned in Input
. We can then create a new figure in function and return it. The returned figure will be set as an attribute of the Output
figure attribute.
We have defined three callback functions below.
Input
and (line chart id, figure attribute) as Output
.Output
is set to (scatter chart id, figure attribute).Input
and (bar chart id, figure attribute) as Output
.from dash.dependencies import Input, Output
@app.callback(Output('graph1', 'figure'), [Input('multi_select_line_chart', 'value')])
def update_line(price_options):
chart1 = go.Figure()
for price_op in price_options:
chart1.add_trace(go.Scatter(x=apple_df.Date, y=apple_df[price_op],
mode="lines", name=price_op))
chart1.update_layout(
xaxis_title="Date",
yaxis_title="Price ($)",
title="Apple Stock Prices [Apr-2019-Mar-2020]",
height=500,)
return chart1
@app.callback(Output('graph2', 'figure'), [Input('dropdown1_scatter_chart', 'value'), Input('dropdown2_scatter_chart', 'value')])
def update_scatter(drop1, drop2):
chart2 = px.scatter(data_frame=wine_df,
x=drop1,
y=drop2,
color="WineType",
title="%s vs %s color-encoded by wine type"%(drop1, drop2),
height=500,
)
return chart2
@app.callback(Output('graph3', 'figure'), [Input('dropdown_bar_chart', 'value')])
def update_bar(bar_drop):
chart3 = px.bar(data_frame=iris_avg_by_flower_type,
x="FlowerType",
y=bar_drop,
title="Avg %s Per Flower Type"%bar_drop,
height=500,
)
return chart3
This ends our step by step process to build a dashboard. We'll now put the whole code together and run the dashboard.
Below we have put down total code into one cell. We can save this code as .py
python file and run it. It'll bring the dashboard up on local on port 8050
by default. We can change the default port to the port of our choice by setting port number into the run_server()
method.
If you are interested in learning steps to deploy dashboard online then feel free to go through our another tutorial on dashboard creation using plotly/dash which explains steps to deploy dashboard on pythonanywhere.com.
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from sklearn.datasets import load_iris, load_wine
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
############ Loading Datasets ##################
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df["FlowerType"] = [iris.target_names[target] for target in iris.target]
wine = load_wine()
wine_df = pd.DataFrame(data=wine.data, columns=wine.feature_names)
wine_df["WineType"] = [wine.target_names[target] for target in wine.target]
apple_df = pd.read_csv("~/datasets/AAPL.csv")
################# Line Chart ##############################
chart1 = go.Figure()
chart1.add_trace(go.Scatter(x=apple_df.Date, y=apple_df.Open,
marker={"color":"tomato"},
mode="lines"))
chart1.update_layout(height=500,
xaxis_title="Date",
yaxis_title="Price ($)",
title="Apple Stock Prices [Apr-2019-Mar-2020]")
################# Scatter Plot ################################
chart2 = px.scatter(data_frame=wine_df,
x=wine.feature_names[0],
y=wine.feature_names[1],
color="WineType",
title="alcohol vs malic_acid color-encoded by wine type",
height=500,
)
################## Bar Chart ###############################
iris_avg_by_flower_type = iris_df.groupby(by="FlowerType").mean().reset_index()
chart3 = px.bar(data_frame=iris_avg_by_flower_type,
x="FlowerType",
y=iris.feature_names[0],
title="Avg %s Per Flower Type"%iris.feature_names[0],
height=500,
)
#################### Creating App Object ############################
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
####################### Setting Graphs as HTML Children ##############
graph1 = dcc.Graph(
id='graph1',
figure=chart1,
#className="eight columns"
)
graph2 = dcc.Graph(
id='graph2',
figure=chart2,
#className="five columns"
)
graph3 = dcc.Graph(
id='graph3',
figure=chart3,
#className="five columns"
)
############### Creating Widgets For Each Graph #########################
multi_select_line_chart = dcc.Dropdown(
id="multi_select_line_chart",
options=[{"value":label, "label":label} for label in ["Open", "Low", "High", "Close"]],
value=["Open"],
multi=True,
clearable = False
)
dropdown1_scatter_chart = dcc.Dropdown(
id="dropdown1_scatter_chart",
options=[{"value":label, "label":label} for label in wine.feature_names],
value=wine.feature_names[0],
className="six columns",
clearable = False
)
dropdown2_scatter_chart = dcc.Dropdown(
id="dropdown2_scatter_chart",
options=[{"value":label, "label":label} for label in wine.feature_names],
value=wine.feature_names[1],
className="six columns",
clearable = False
)
dropdown_bar_chart = dcc.Dropdown(
id="dropdown_bar_chart",
options=[{"value":label, "label":label} for label in iris.feature_names],
value=iris.feature_names[0],
clearable = False
)
######################### Laying out Charts & Widgets to Create App Layout ##########
header = html.H2(children="Simple Dashboard With Widgets")
row1 = html.Div(children=[multi_select_line_chart, graph1], className="eight columns")
scatter_div = html.Div(children=[html.Div(children=[dropdown1_scatter_chart, dropdown2_scatter_chart], className="row") , graph2], className="six columns")
bar_div = html.Div(children=[dropdown_bar_chart, graph3], className="six columns")
row2 = html.Div(children=[scatter_div, bar_div], className="eight columns")
layout = html.Div(children=[header, row1, row2], style={"text-align": "center", "justifyContent":"center"})
############### Setting App Layout ########################################
app.layout = layout
################## Creating Callbacks for Each Widget ############################
@app.callback(Output('graph1', 'figure'), [Input('multi_select_line_chart', 'value')])
def update_line(price_options):
chart1 = go.Figure()
for price_op in price_options:
chart1.add_trace(go.Scatter(x=apple_df.Date, y=apple_df[price_op],
mode="lines", name=price_op))
chart1.update_layout(
xaxis_title="Date",
yaxis_title="Price ($)",
title="Apple Stock Prices [Apr-2019-Mar-2020]",
height=500,)
return chart1
@app.callback(Output('graph2', 'figure'), [Input('dropdown1_scatter_chart', 'value'), Input('dropdown2_scatter_chart', 'value')])
def update_scatter(drop1, drop2):
chart2 = px.scatter(data_frame=wine_df,
x=drop1,
y=drop2,
color="WineType",
title="%s vs %s color-encoded by wine type"%(drop1, drop2),
height=500,
)
return chart2
@app.callback(Output('graph3', 'figure'), [Input('dropdown_bar_chart', 'value')])
def update_bar(bar_drop):
chart3 = px.bar(data_frame=iris_avg_by_flower_type,
x="FlowerType",
y=bar_drop,
title="Avg %s Per Flower Type"%bar_drop,
height=500,
)
return chart3
################## Running App #####################################
if __name__ == "__main__":
app.run_server(debug=True)
This ends our small tutorial explaining basic dashboard creation using plotly and dash with widgets. Please feel free to let us know your views in the comments section.
If you are more comfortable learning through video tutorials then we would recommend that you subscribe to our YouTube channel.
When going through coding examples, it's quite common to have doubts and errors.
If you have doubts about some code examples or are stuck somewhere when trying our code, send us an email at coderzcolumn07@gmail.com. We'll help you or point you in the direction where you can find a solution to your problem.
You can even send us a mail if you are trying something new and need guidance regarding coding. We'll try to respond as soon as possible.
If you want to