Developing Interactive and Insightful Dashboards with Spark and Plotly Dash | by Yu Huang, M.D., M.S. in CS | Jun, 2023


The previous section describes how to create dashboards with different types of graphs using Plotly Express library on a cluster of Spark servers. This section shows how to use Dash to share dashboards with Web application clients and allow clients to use the dashboards to visualize data in various ways interactively.

The following procedure can be followed to develop a one page dashboard of a Web application:

  • Step 1: import Dash library modules
  • Step 2: create a Dash application object
  • Step 3: define a dashboard layout of HTML page
  • Step 4: define callback functions (Web service end points)
  • Step 5: start server

4.1 Import Dash Library Modules

As the first step, the Plotly Dash library modules are imported as follows for the purpose of demonstration in this paper.

import plotly.express as px
from dash import Dash, dcc, html, callback, Input, Output

4.2 Create Dash Application Object

After importing library modules, the next step is to create a Dash application object:

app = Dash(__name__)

4.3 Define Dashboard Layout

Once a Dash application object is created, we need to define a dashboard layout as a HTML page.

The dashboard HTML page is divided into two parts in this paper:

  • Part 1: visualization of numeric features
  • Part 2: visualization of categorical features

Part 1 of the dashboard layout is defined as follows:

app.layout = html.Div([ # dashboard layout
html.Div([ # Part 1
html.Div([
html.Label(['Age:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['0-10', '11-20', '21-30', '31-40', '41-50',
'51-60', '61-70', '71-80', '81-90', '91-100',
'More than 100 Days'],
value='21-30',
id='numerical_age'
),
],
style={'width': '20%', 'display': 'inline-block'}),

html.Div([
html.Label(['Numerical Feature x:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['patientid',
'Hospital_code',
'City_Code_Hospital'],
value='patientid',
id='axis_x',
)
], style={'width': '20%', 'display': 'inline-block'}),

html.Div([
html.Label(['Numerical Feature y:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['Hospital_code',
'Admission_Deposit',
'Bed Grade',
'Available Extra Rooms in Hospital',
'Visitors with Patient',
'Bed Grade',
'City_Code_Patient'],
value='Admission_Deposit',
id='axis_y'
),
], style={'width': '20%', 'display': 'inline-block'}),

html.Div([
html.Label(['Color Feature:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['Severity of Illness',
'Stay',
'Department',
'Ward_Type',
'Ward_Facility_Code',
'Type of Admission',
'Hospital_region_code'],
value='Type of Admission',
id='color_feature'
),
], style={'width': '20%', 'display': 'inline-block'}),

html.Div([
html.Label(['Graph Style:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['scatter',
'histogram',
'line'],
value='histogram',
id='numerical_graph_style'
),
], style={'width': '20%', 'float': 'right', 'display': 'inline-block'})
],
style={
'padding': '10px 5px'
}),

html.Div([
dcc.Graph(id='numerical-graph-content')
]),
......

Figures 2, 3, and 4 are created by using Part 1 of the dashboard layout.

Part 2 of the dashboard layout is defined as follows:

......
html.Div([ # Part 2
html.Div([
html.Label(['Age:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['0-10', '11-20', '21-30', '31-40', '41-50',
'51-60', '61-70', '71-80', '81-90', '91-100',
'More than 100 Days'],
value='21-30',
id='categorical_age'
),
],
style={'width': '25%', 'display': 'inline-block'}),

html.Div([
html.Label(['Categorical Feature:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['Severity of Illness',
'Stay',
'Department',
'Ward_Type',
'Ward_Facility_Code',
'Type of Admission',
'Hospital_region_code'],
value='Stay',
id='categorical_feature'
),
],
style={'width': '25%', 'display': 'inline-block'}),

html.Div([
html.Label(['Color:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown(
['red',
'green',
'blue',
'orange',
'purple',
'black',
'yellow'],
value='blue',
id='categorical_color'
),
],
style={'width': '25%', 'display': 'inline-block'}),

html.Div([
html.Label(['Graph Style:'], style={'font-weight': 'bold', "text-align": "center"}),
dcc.Dropdown([
'histogram',
'bar',
'line',
'pie'],
value='bar',
id='categorical_graph_style'
),
],
style={'width': '25%', 'float': 'right', 'display': 'inline-block'})
],
style={
'padding': '10px 5px'
}),

html.Div([
dcc.Graph(id='categorical-graph-content')
])
]) # end of dashboard layout

Figures 5, 6, and 7 are created by using Part 2 of the dashboard layout.

4.4 Define Callback Functions

The dashboard layout only creates a static HTML page of a dashboard. Callback functions (i.e., Web service end points) must be defined so that a dashboard user’s action can be sent to a server-side callback function as a Web service request. In other words, callback functions enable interaction between dashboard users and server-side dashboard Web services such as creating a new graph upon user request (e.g., select a dropdown choice).

There are two callback functions defined in this paper for the two parts of the dashboard layout.

The callback function for Part 1 of the dashboard layout is defined as follows:

@callback(
Output('numerical-graph-content', 'figure'),
Input('axis_x', 'value'),
Input('axis_y', 'value'),
Input('numerical_age', 'value'),
Input('numerical_graph_style', 'value'),
Input('color_feature', 'value')
)
def update_numerical_graph(x, y, age, graph_style, color_feature):
dff = spark.sql(f"SELECT * FROM dataset_view WHERE Age=='{age}'").toPandas()

if graph_style == 'line':
fig = px.line(dff,
x = x,
y = y,
color = color_feature
)
elif graph_style == 'histogram':
fig = px.histogram(dff,
x = x,
y = y,
color = color_feature
)
else:
fig = px.scatter(dff,
x = x,
y = y,
color = color_feature
)

fig.update_layout(
title=f"Relationship between {x} vs. {y}",
)

return fig

The callback function for Part 2 of the dashboard layout is defined as follows:

@callback(
Output('categorical-graph-content', 'figure'),
Input('categorical_feature', 'value'),
Input('categorical_age', 'value'),
Input('categorical_graph_style', 'value'),
Input('categorical_color', 'value')
)
def update_categorical_graph(feature, age, graph_style, color):
dff = spark.sql(f"SELECT * FROM dataset_view WHERE Age=='{age}'").toPandas()
vc = dff[feature].value_counts()

if graph_style == 'bar':
fig = px.bar(vc,
x = vc.index,
y = vc.values
)
elif graph_style == 'histogram':
fig = px.histogram(vc,
x = vc.index,
y = vc.values
)
elif graph_style == 'line':
fig = px.line(vc,
x = vc.index,
y = vc.values
)
else:
fig = px.pie(vc,
names = vc.index,
values = vc.values
)

if graph_style == 'line':
fig.update_traces(line_color=color)
elif graph_style != 'pie':
fig.update_traces(marker_color=color)

fig.update_layout(
title=f"Feature {feature} Value Counts",
xaxis_title=feature,
yaxis_title="Count"
)

return fig

Each callback function is associated with an annotation @callback. The annotation associated with a callback function controls which HTML components (e.g., dropdown) provide inputs to the callback function upon users’ request, and which HTML component (e.g., a graph within a div tag) receives the output of the callback function.

4.5 Start Server

The final step of a Dash Web application is to start a Web service server as below:

if __name__ == "__main__":
app.run_server()

The following diagram shows one scenario of the dashboard when a dashboard user has selected the following choices in the dashboard:

  • age from 21 to 30
  • pair of numeric features patientid and Admission_Deposit
  • categorical feature Type of Admission for color coding of numeric features visualization
  • scatter plot for numeric features visualization
  • Categorical feature Stay for calculating featue value counts
  • Color blue for bar, histogram, and line chart
  • pie graph with automatic color coding for visualization of categorical feature value counts



Source link

Leave a Comment